mem0 icon indicating copy to clipboard operation
mem0 copied to clipboard

Fix: Prevent saving prompt artifacts as memory when no new facts are …

Open chaithanyak42 opened this issue 7 months ago • 0 comments

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 calls memory.add() with a "fact-less" input (e.g., "Hi there").
    • Verification:
      1. 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.
      2. 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., OpenAI gpt-4o-mini for fact extraction and memory updates, requiring an OPENAI_API_KEY).
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

chaithanyak42 avatar May 21 '25 08:05 chaithanyak42