MemorySync
Getting Started

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

LayerWhat it does
MemorySyncMemoryA 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.
MemorySyncMemoryBlockThe recall/persist block alone, for composing into your own Memory(memory_blocks=[...]) — with REAL partial truncation.
MemorySyncRetrieverMemories as a genuine BaseRetriever for RetrieverQueryEngine, RetrieverTool and anything else that consumes retrievers.
Agent tools + helperscreate_memorysync_tools() — five never-raise FunctionTools — and sync helpers get_memory_context, search_memories, save_turn.
Mem0SupermemoryZepMemorySync
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 FunctionAgent
from llama_index.llms.openai import OpenAI
from llamaindex_memorysync import MemorySyncMemory
memory = MemorySyncMemory.from_defaults(
user_id="customer-7", # per-end-user scoping — required
session_id="thread-42", # groups the stored transcript
)
agent = FunctionAgent(tools=[...], llm=OpenAI(model="gpt-4o-mini"))
# First conversation
await agent.run("I'm vegetarian and I fly aisle.", memory=memory)
# Any later run — same user, any thread, any deploy
response = 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 Memory
from llamaindex_memorysync import MemorySyncMemoryBlock
memory = 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 RetrieverQueryEngine
from llama_index.core.tools import RetrieverTool
from llamaindex_memorysync import MemorySyncRetriever
retriever = MemorySyncRetriever(user_id="customer-7", similarity_top_k=5)
# Raw scored nodes
nodes = retriever.retrieve("dietary preferences")
# [NodeWithScore(node=TextNode(text="human: I'm vegetarian", ...), score=0.62)]
# A query engine over memories
engine = 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 call
tool = 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 FunctionAgent
from llamaindex_memorysync import create_memorysync_tools
agent = 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)
ToolWhat it doesFailure behaviour
add_memorySave one durable fact; duplicate saves answer “already stored”.Readable error string — never raises.
search_memorySemantic search with relevance scores.Readable error string.
list_memoriesNewest-first listing.Readable error string.
update_memoryChange tags/importance. Memory text is immutable.Readable error string.
delete_memoryPermanent 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 results
hits = 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

ExportKindNotes
MemorySyncMemoryMemory subclassfrom_defaults(user_id=..., session_id, recall, persist, mode, k, template, on_error, **memory_kwargs) — every standard Memory kwarg passes through.
MemorySyncMemoryBlockMemory blockComposable into any Memory; mode, k, template, priority; real partial atruncate.
MemorySyncRetrieverBaseRetrieveruser_id + similarity_top_k (1-50); sync and async retrieval.
create_memorysync_toolsTool factoryFive FunctionTools; read_only=True returns search + list only.
get_memory_context / search_memories / save_turnSync helperssave_turn raises on failure; all share the memory classes’ seeds.
MemorySyncAPIErrorExceptionCarries the HTTP status and server detail.

Supported versions

PackageRegistryRequiresRuntime
llamaindex-memorysync 1.0.0PyPIllama-index-core >=0.13 <0.15Python 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.

Where to go next

Was this page helpful?