Fix: Prevent saving prompt artifacts as memory when no new facts are …
Description
This change addresses an issue where parts of an internal system prompt were being incorrectly saved as new memory items. This occurred under specific conditions in the Memory._add_to_vector_store() method when no new facts were extracted from user input and no relevant existing memories were found.
The core problem was that even with an empty list of new_retrieved_facts, the system would proceed to a subsequent LLM call intended for memory update decisions (ADD/UPDATE/DELETE). This second LLM, when presented with a prompt containing its own instructional text but no actual data to process, would sometimes misinterpret the instructional text (e.g., "The new retrieved facts are mentioned in the triple backticks.") as a new fact to be added to memory.
This fix introduces a guard condition: if new_retrieved_facts is empty after the initial fact extraction step, the method now returns early, preventing the problematic second LLM call and the erroneous memory creation.
Fixes # #2736
Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
How Has This Been Tested?
The fix has been verified through the following:
- [x] Test Script: A dedicated test script (
test_fix.py) was created and executed.- Instructions: The script initializes
mem0.Memory, clears memories for a test user, and then callsmemory.add()with a "fact-less" input (e.g., "Hi there"). - Verification:
- The script checks application logs for the message "No new facts retrieved from input. Skipping memory update LLM call.", confirming the fix's logic path was taken.
- It then calls
memory.get_all()for the test user and asserts that the problematic prompt string ("The new retrieved facts are mentioned in the triple backticks.") is NOT present in the stored memories.
- Configuration: The test script uses a standard
mem0.Memory()setup with default LLM configurations (e.g., OpenAIgpt-4o-minifor fact extraction and memory updates, requiring anOPENAI_API_KEY).
- Instructions: The script initializes
import logging
from openai import OpenAI
from mem0 import Memory
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
mem0_logger = logging.getLogger("mem0")
mem0_logger.setLevel(logging.INFO)
openai_client = OpenAI()
memory = Memory()
TEST_USER_ID = "test_user_readme_bugfix_001"
def chat_with_memories_for_test(message: str, user_id: str) -> str:
relevant_memories = memory.search(query=message, user_id=user_id, limit=3)
logging.info(f"For user '{user_id}', search for '{message}' found: {relevant_memories}")
memories_str = "\n".join(f"- {entry['memory']}" for entry in relevant_memories.get("results", []))
# Generate Assistant response
system_prompt = f"You are a helpful AI. Answer the question based on query and memories.\nUser Memories:\n{memories_str}"
messages_for_llm = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": message}
]
logging.info(f"Sending to OpenAI: {messages_for_llm}")
response = openai_client.chat.completions.create(model="gpt-4o-mini", messages=messages_for_llm)
assistant_response = response.choices[0].message.content
logging.info(f"OpenAI Assistant response: {assistant_response}")
messages_to_add_to_memory = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": message},
{"role": "assistant", "content": assistant_response}
]
logging.info(f"Adding to mem0 memory for user '{user_id}': {messages_to_add_to_memory}")
memory.add(messages_to_add_to_memory, user_id=user_id) # infer=True is default
return assistant_response
def run_test():
print(f"--- Starting test for user_id: {TEST_USER_ID} ---")
print(f"Resetting memories for user: {TEST_USER_ID} (if any)")
try:
memory.delete_all(user_id=TEST_USER_ID)
print("Old memories for test user deleted.")
except ValueError as e:
# This can happen if the user_id doesn't exist or has no memories, which is fine.
print(f"Note: Could not delete memories for {TEST_USER_ID} (may be first run): {e}")
except Exception as e:
print(f"Error deleting memories for test user: {e}")
user_input = "Hi there" # A "fact-less" input
print(f"You: {user_input}")
ai_response = chat_with_memories_for_test(user_input, user_id=TEST_USER_ID)
print(f"AI: {ai_response}")
print(f"\n--- Verifying memories for user_id: {TEST_USER_ID} ---")
all_user_memories = memory.get_all(user_id=TEST_USER_ID)
print("\nRetrieved memories:")
if all_user_memories and all_user_memories.get("results"):
for mem_item in all_user_memories["results"]:
print(f" - ID: {mem_item.get('id')}, Memory: \"{mem_item.get('memory')}\", Event: {mem_item.get('event', 'N/A')}")
if "The new retrieved facts are mentioned in the triple backticks." in mem_item.get('memory', ''):
print(" !!!!!!!! ERROR: Problematic string found in memory !!!!!!!!");
else:
print(" No memories found for this user.")
print("\n--- Test Finished ---")
print("Check the console output above for log messages from 'mem0.memory.main',")
print("especially looking for 'No new facts retrieved from input. Skipping memory update LLM call.'")
print("Also, verify that the problematic string was not saved as a memory.")
if __name__ == "__main__":
run_test()
Checklist:
- [x] My code follows the style guidelines of this project
- [x ] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas (The fix is a straightforward conditional check, well-covered by the commit message and this PR description.)
- [x] I have made corresponding changes to the documentation (No documentation changes required for this internal logic fix.)
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my feature works (a manual test script was used)
- [x] New and existing unit tests pass locally with my changes
- [x] Any dependent changes have been merged and published in downstream modules (No such dependencies for this change.)
- [x] I have checked my code and corrected any misspellings
Maintainer Checklist
- [ ] closes #xxxx (Replace xxxx with the GitHub issue number)
- [ ] Made sure Checks passed