LlamaIndex Memory
LlamaIndex’s Memory, upgraded: every turn persists to durable server-side memory the moment it happens (not when a token buffer eventually overflows), recall injects through the native memory-block template, and memories double as a genuine retriever for RAG — plus five agent memory tools.
What the integration provides
| Layer | What it does |
|---|---|
MemorySyncMemory | A subclass of LlamaIndex’s Memory for agent.run(..., memory=...): short-term buffer and every standard option intact, with durable MemorySync persistence on every aput and recall injected via the native block template. |
MemorySyncMemoryBlock | The recall/persist block alone, for composing into your own Memory(memory_blocks=[...]) — with REAL partial truncation. |
MemorySyncRetriever | Memories as a genuine BaseRetriever for RetrieverQueryEngine, RetrieverTool and anything else that consumes retrievers. |
| Agent tools + helpers | create_memorysync_tools() — five never-raise FunctionTools — and sync helpers get_memory_context, search_memories, save_turn. |
| Mem0 | Supermemory | Zep | MemorySync | |
|---|---|---|---|---|
| Integration exists | ✓ llama-index-memory-mem0 | ✗ nothing | △ vector store only | ✓ memory + block + retriever + tools |
from_defaults works | ✗ raises NotImplementedError | — | — | ✓ |
| Async-native | ✗ sync only | — | — | ✓ async end to end, sync wrappers included |
| Composes with memory blocks | ✗ replaces the memory wholesale | — | — | ✓ IS a Memory; blocks compose |
| Short conversations persist | ✓ | — | — | ✓ immediately, on every aput |
| Partial truncation under token pressure | ✗ | — | — | ✓ drops lowest-value lines, never the whole block |
Install
pip install llamaindex-memorysync
Set MEMORYSYNC_API_KEY in the environment, or pass api_key explicitly. Requires llama-index-core 0.13+ (installed automatically; Python 3.10+). This is a Python surface — for TypeScript agents use the Vercel AI SDK or Mastra integrations.
The upgraded Memory
from llama_index.core.agent.workflow import FunctionAgentfrom llama_index.llms.openai import OpenAIfrom llamaindex_memorysync import MemorySyncMemorymemory = MemorySyncMemory.from_defaults(user_id="customer-7", # per-end-user scoping — requiredsession_id="thread-42", # groups the stored transcript)agent = FunctionAgent(tools=[...], llm=OpenAI(model="gpt-4o-mini"))# First conversationawait agent.run("I'm vegetarian and I fly aisle.", memory=memory)# Any later run — same user, any thread, any deployresponse = await agent.run("Book my trip: flight plus a dinner spot.", memory=memory)# The model already saw: vegetarian, aisle seat — injected from memory.
Everything Memory does still works — token_limit, insert_method, your own additional blocks — because MemorySyncMemory IS a Memory, not a wrapper around one. Only user and assistant text persists to long-term memory; system prompts and tool traffic stay in the short-term buffer where they belong. recall=False and persist=False switch either half off.
Or compose the block
from llama_index.core.memory import Memoryfrom llamaindex_memorysync import MemorySyncMemoryBlockmemory = Memory.from_defaults(session_id="thread-42",memory_blocks=[MemorySyncMemoryBlock(user_id="customer-7"),# ...alongside any other blocks you already run],)# Recall renders into the framework's own <memory> template;# messages the buffer flushes into the block persist durably —# with the same seeds as MemorySyncMemory, so mixing never# double-stores a turn.
Under token pressure the framework truncates blocks by priority — and its default truncation DELETES a block entirely. MemorySyncMemoryBlock.atruncate drops the lowest-value lines instead (recall orders best-first), so the prompt keeps the memories that matter.
Memories as a retriever
from llama_index.core.query_engine import RetrieverQueryEnginefrom llama_index.core.tools import RetrieverToolfrom llamaindex_memorysync import MemorySyncRetrieverretriever = MemorySyncRetriever(user_id="customer-7", similarity_top_k=5)# Raw scored nodesnodes = retriever.retrieve("dietary preferences")# [NodeWithScore(node=TextNode(text="human: I'm vegetarian", ...), score=0.62)]# A query engine over memoriesengine = RetrieverQueryEngine.from_args(retriever=retriever, llm=llm)answer = engine.query("What do we know about this customer's diet?")# Or a tool an agent can calltool = RetrieverTool.from_defaults(retriever=retriever,name="memory_search",description="Search everything known about this user.",)
A genuine BaseRetriever — sync and async, with node metadata carrying the memory id and user. It raises on API failure rather than returning an empty list, because “no memories” and “the memory service errored” must never look identical to a RAG pipeline.
Agent memory tools
from llama_index.core.agent.workflow import FunctionAgentfrom llamaindex_memorysync import create_memorysync_toolsagent = FunctionAgent(tools=create_memorysync_tools(user_id="customer-7"),llm=llm,system_prompt="Use the memory tools to remember durable facts.",)await agent.run("Remember that I prefer aisle seats.")# Untrusted agents: search + list only.create_memorysync_tools(user_id="customer-7", read_only=True)
| Tool | What it does | Failure behaviour |
|---|---|---|
add_memory | Save one durable fact; duplicate saves answer “already stored”. | Readable error string — never raises. |
search_memory | Semantic search with relevance scores. | Readable error string. |
list_memories | Newest-first listing. | Readable error string. |
update_memory | Change tags/importance. Memory text is immutable. | Readable error string. |
delete_memory | Permanent delete by id, scoped to the configured user. | Readable error string. |
Same five operations, same response strings as the LangChain, AI SDK, CrewAI, Mastra and OpenAI Agents tool sets — an agent moved between frameworks keeps behaving the same way.
Standalone helpers
from llamaindex_memorysync import (get_memory_context,save_turn,search_memories,)# 1. Prompt-ready context block ("" for a new user)context = get_memory_context("what should I cook?", user_id="customer-7")# 2. Scored raw resultshits = search_memories("dietary preferences", user_id="customer-7")# 3. Explicit persistence — RAISES on failure (an explicit call is# owed the truth), unlike the memory classes' degrading planes.save_turn(user_id="customer-7",user="I'm vegetarian",assistant="Noted!",session_id="thread-42",)
Public API
| Export | Kind | Notes |
|---|---|---|
MemorySyncMemory | Memory subclass | from_defaults(user_id=..., session_id, recall, persist, mode, k, template, on_error, **memory_kwargs) — every standard Memory kwarg passes through. |
MemorySyncMemoryBlock | Memory block | Composable into any Memory; mode, k, template, priority; real partial atruncate. |
MemorySyncRetriever | BaseRetriever | user_id + similarity_top_k (1-50); sync and async retrieval. |
create_memorysync_tools | Tool factory | Five FunctionTools; read_only=True returns search + list only. |
get_memory_context / search_memories / save_turn | Sync helpers | save_turn raises on failure; all share the memory classes’ seeds. |
MemorySyncAPIError | Exception | Carries the HTTP status and server detail. |
Supported versions
| Package | Registry | Requires | Runtime |
|---|---|---|---|
llamaindex-memorysync 1.0.0 | PyPI | llama-index-core >=0.13 <0.15 | Python 3.10+ |
The test suite exercises the real llama-index-core memory machinery — the waterfall flush, the block template, RetrieverQueryEngine with a mock LLM — and CI re-runs it against the latest core release within the supported range on every push, so an upstream memory-architecture change fails our pipeline before it can fail your agent.