nat-memorysync
MemorySync memory backend for the NVIDIA NeMo Agent Toolkit (nvidia-nat).
Registers a memorysync_memory client that plugs into workflow YAML as a
memory: section entry — usable from the toolkit's built-in add_memory /
get_memory tools, from the automatic auto_memory_agent wrapper, and from
any custom function that requests a memory client from the Builder.
pip install nat-memorysync
Requires Python 3.11+ (the toolkit's own floor). Installing this package pulls
nvidia-nat-core; install nvidia-nat (or the plugin subpackages you need)
for the full toolkit.
Why this instead of the in-repo editors?
The toolkit ships example editors for Mem0 and Zep. Both have sharp edges we designed against:
| Behavior | Mem0 (in-repo) | Zep (in-repo) | nat-memorysync |
|---|---|---|---|
search() without user_id |
bare KeyError |
n/a (thread-scoped) | ValueError naming the kwarg |
| Multi-user isolation with no conversation id | per-call user_id |
all users share "default_zep_thread" |
rows always keyed by item user_id — bleed impossible |
Your metadata dict after add_items |
mutated (keys popped out) | untouched | untouched (copy-first, tested) |
| Search result shape | items, scores discarded | one joined text blob | one MemoryItem per fact, similarity_score populated |
remove_items() with no kwargs |
silent no-op | deletes current thread | raises — refuses to guess |
| Delete blast radius | whole user | whole thread | session-scoped by default; whole user requires explicit scope="user" |
| Slow/down memory backend | blocks the turn | blocks the turn | 1.2 s recall budget, fail-open both directions |
| Retried writes | duplicated | duplicated | deterministic idempotency seeds — a retried turn is recognised and extracted once |
Wiring mode 1 — explicit memory tools
The agent decides when to store and when to recall:
memory:
saas_memory:
_type: memorysync_memory # key comes from MEMORYSYNC_API_KEY env var
functions:
add_memory:
_type: add_memory
memory: saas_memory
description: Save any user preference or fact for later conversations.
get_memory:
_type: get_memory
memory: saas_memory
description: Recall previously saved user preferences and facts.
workflow:
_type: react_agent
tool_names: [add_memory, get_memory]
llm_name: my_llm
Wiring mode 2 — automatic memory (auto_memory_agent)
No tools, no prompt changes — every user message is sent to fact extraction
(assistant replies are not stored as memories) and every prompt is enriched
automatically (requires nvidia-nat-langchain):
memory:
saas_memory:
_type: memorysync_memory
workflow:
_type: auto_memory_agent
augmented_fn: my_actual_workflow
memory: saas_memory
search runs inside a hard 1.2 s budget here, so automatic memory can never
stall a turn.
Builder API (Python)
from nat.builder.workflow_builder import WorkflowBuilder
from nat_memorysync import MemorySyncMemoryConfig
async with WorkflowBuilder() as builder:
await builder.add_memory_client("saas_memory", MemorySyncMemoryConfig())
editor = await builder.get_memory_client("saas_memory")
from nat.memory.models import MemoryItem
await editor.add_items([
MemoryItem(
conversation=[{"role": "user", "content": "I prefer teal dashboards"}],
user_id="customer-1",
metadata={"plan": "pro"},
)
])
items = await editor.search("dashboard preferences", top_k=5, user_id="customer-1")
for it in items:
print(it.similarity_score, it.memory)
Configuration
All fields are optional except the API key (env var or config field):
| YAML field | Default | Purpose |
|---|---|---|
api_key |
MEMORYSYNC_API_KEY env var |
API key — keep it in the env var so YAML stays credential-free |
base_url |
https://api.memorysync.io |
Override for self-hosted / staging |
project_id |
– | Optional X-Project-ID header |
top_k |
5 |
Default memories per search |
recall_timeout |
1.2 |
Hard recall budget (seconds); slow backend degrades to no memories |
min_query_chars |
8 |
Skip recall for shorter queries |
source |
nat |
Source label on the memories this client writes |
MemoryBaseConfig + RetryMixin knobs (num_retries,
retry_on_status_codes, …) work too — retries are safe because every turn
carries a deterministic idempotency seed: the server recognises a retried
turn and extracts it once.
Editor semantics
add_items(items)— the user turns of eachMemoryItem.conversationare sent to MemorySync's fact extraction (facts, dedup, decay), scoped to that item'suser_id; only the durable facts found are stored, never the turn text itself. Assistant replies are not stored as memories, so assistant (and system/tool) turns are not sent. Scalarmetadatavalues ride along onto the facts;metadata.ignore_roleslists roles to skip and is never forwarded. An item with onlymemoryset goes through the extraction path too, where the server decides what is durable. Items that fail to send are logged and skipped — a partial batch never raises mid-turn.search(query, top_k=..., user_id=...)— semantic recall, oneMemoryItemper fact withsimilarity_score.user_idis required (loudValueError, not aKeyError).remove_items(user_id=...)— deletes the user's memories labelled with this adapter's session (the facts extracted from the turns it sent carry the label). Addmemory_id="..."for one row, orscope="user"to wipe the user's entire memory (explicit opt-in). No kwargs →ValueError.
Session scope comes from the toolkit's Context.get().conversation_id
ContextVar when set (nat::<conversation_id>), else nat::default — but
every write is additionally keyed by user_id, so an unset conversation id
can never mix users.
Tests
pip install -e . nvidia-nat-core langchain-core pytest pytest-asyncio "httpx>=0.25,<1"
pytest tests -q # 31 tests
The suite exercises the real WorkflowBuilder, NVIDIA's real
add_memory/get_memory tool functions driving this editor end to end, plus
named regression tests for every competitor bug in the table above.
License
MIT © MemorySync.
Metadata
Release files for nat-memorysync 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nat_memorysync-1.1.0.tar.gz | 20.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nat_memorysync-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 34.8 kB
Release files / nat_memorysync-1.1.0.tar.gz
| Download URL | nat_memorysync-1.1.0.tar.gz |
|---|---|
| Size | 20.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
71d6dbb51a5f472019ba731c4e87ec39abd30c393241b281e34457009403209e
|
|
BLAKE2b-256 checksum How to use checksums |
3d474849ec5d92e2f6f27fbae00da654893508f08741293fc0654ed9af107ac8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.5
|
Release files / nat_memorysync-1.1.0-py3-none-any.whl
| Download URL | nat_memorysync-1.1.0-py3-none-any.whl |
|---|---|
| Size | 14.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
49a5e1aa9276e74f50c5f1378cf972b12208c0fd161c326186e1e0224b7b2e5e
|
|
BLAKE2b-256 checksum How to use checksums |
58696c559747481e7492a04fc70862cb2b4d4a567729332181e7268d5237d746
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.5
|