MemorySync
Integrations

Strands Agents Memory

Give Strands Agents long-term memory in three lines. The store plugs into Strands’ own MemoryManager: relevant memories are injected automatically before every model call under a hard latency budget, and the user’s messages are sent for fact extraction turn by turn — with zero framework dependencies.

MemoryManager uses MemorySyncStore for automatic recall, turn-by-turn extraction, and safe search and save tools.

How it works

  1. Install strands-memorysync from PyPI.
  2. Create a MemorySyncStore with your API key and the end user’s id.
  3. Hand it to the agent via MemoryManager(stores=[store]).
  4. Done — the manager consults the store before every model call (automatic injection, not tool-gated) and hands each exchange to the store, which sends the user’s messages for fact extraction. The agent’s replies are not stored. No per-turn code.

Before you start

  1. A MemorySync API key. Create one in the dashboard under Settings → API Keys, inside a project.
  2. Python 3.10+ with a strands-agents release that ships the MemoryManager seam (2026+). The store itself has zero framework dependencies, so it can never version-conflict with your Strands release.

Install

One package:

Terminal
pip install strands-memorysync

Quickstart

Step 1 — create the store

The store is where you say whose memories these are. user_id is required; session_id separates conversations — every distilled fact is tagged with it.

store.py
from strands_memorysync import MemorySyncStore
store = MemorySyncStore(
api_key="ms_...", # or set MEMORYSYNC_API_KEY in the environment
user_id="customer-42", # required — the end user these memories belong to
session_id="support", # optional — tags this conversation's facts
)

Step 2 — attach it to your agent

Hand the store to the MemoryManager. From now on every model call is preceded by an automatic memory lookup, and the user’s side of every exchange flows into fact extraction — recallable from the very first turn.

agent.py
from strands import Agent
from strands.memory import MemoryManager
agent = Agent(memory_manager=MemoryManager(stores=[store]))
agent("Which seat should I book?")

Turn-by-turn extraction — no first-turn amnesia

Strands hands conversation turns to the store’s extraction sink when its extraction trigger fires. The default trigger fires every five invocations (the synchronous agent(...) entry point also flushes after each call; invoke_async does not), and zep-strands keeps that five-turn batch, so a user’s first exchanges are simply not sent yet — early recalls return nothing by design. MemorySync’s turn writes are cheap and idempotent (deterministic seeds mean a manager retry is recognised and not extracted twice), so an invocation trigger is safe and recommended: memories are recallable from the very first exchange.

store.py
from strands.memory import InvocationTrigger
store = MemorySyncStore(
user_id="customer-42",
extraction={"trigger": InvocationTrigger()}, # send every turn as it happens
)

Each user message in a batch goes to MemorySync as plain text with role: "user" under the strands::<session> session scope; the server extracts the durable facts it contains and stores only those. Assistant replies are not sent, and a batch with nothing the user said makes no request at all.

GuaranteeHow
A model call is never stalledsearch waits at most recall_timeout (default 1.2s; the very first call of a fresh process gets a one-time 3s grace for connection setup), then fails open to no memories
A memory outage never breaks the agentsearch returns []; extraction logs and continues — no AggregateMemoryError into your code
A manager retry is not extracted twiceSeeds from role + session + content hash, recognised server-side; sequence_numbers travel as each user turn’s sequence metadata
Only the user’s words are sentAssistant replies are not sent; tool and system messages never are
Prompt injection cannot destroy dataNo delete tool exists; deletion stays a human/API action

Optional: memory as agent tools

The manager exposes its own managed search tool by default. If you want the model to search or save explicitly, the store offers a ready-made pair — search and save, never delete. The official Mem0 strands tool exposes a model-callable delete action, which means one prompt injection can wipe a user’s memories; here deletion stays a human/API action, and the user identity is never a tool parameter.

tools.py
tools = store.get_tools() # memorysync_search + memorysync_save

Configuration

ParameterDefaultMeaning
user_id— (required)End user the memories belong to
session_iddefaultSession scope strands::<session> — tags this conversation’s facts
top_k5Memories considered per model call
recall_timeout1.2Hard recall budget in seconds
min_prompt_chars8Skip recall for trivial queries
writableTrueAllow the extraction sink to send user messages for fact extraction
extractionTrueStrands extraction wiring — {"trigger": InvocationTrigger()} recommended for turn-by-turn extraction
expose_toolsTrueReturn memorysync_search/memorysync_save from get_tools()

Choosing a user_id

The user_id is a stable string you pick to identify whose memories these are: your app’s internal user ID, an email address, or a UUID. Use the same value across sessions or recall returns nothing. It also powers per-user isolation — one customer’s memories can never reach another’s agent.

Quotas and plan limits

Hitting a monthly plan limit never breaks the agent. On free and paid plans, over-limit writes are accepted without storing and reads return empty — the conversation continues. Evaluation keys instead surface a truthful 429, so you find out during testing, not in production.

Troubleshooting

  • `ModuleNotFoundError: strands` — the framework itself isn’t installed: pip install strands-agents.
  • Recall returns nothing right after storing — extraction is asynchronous; give it a moment. Also confirm store and recall use the same user_id.
  • Early recalls empty — that’s five-turn batching, the Strands default; set extraction={"trigger": InvocationTrigger()} (from strands.memory) and memories land from the first exchange.
  • `Agent.__init__` crashes with other adapters’ stores — a zep-strands event-loop bug; this store’s initialize() is deliberately inert (a test asserts zero network calls there).
  • The model tried to delete memories — it can’t: no delete tool exists by design.

Supported versions

SurfaceRequiresVerified on
strands-memorysync 1.1.0A strands-agents release with the MemoryManager seam (2026+, Python 3.10+); the store itself has no framework dependency26 CI checks against the latest strands-agents: the REAL MemoryManager search path and a REAL Agent turn via a stub Model — injected context verifiably reaching the model, only the user’s message sent (the reply never), the inert-initialize regression (zep-strands’ event-loop crash), fail-open search under the two-phase budget, seeded duplicate-proof extraction with sequence metadata, the no-delete-tool assertion, and both monthly-quota server modes

How it compares

Mem0 (`mem0_memory` tool)Zep (`zep-strands`)SupermemoryMemorySync
Automatic injection✗ tool-gated — the LLM must decide to recall✓— nothing at all✓
initialize() safety—✗ shipped an event-loop crash (fix unreleased)—✓ deliberately inert; a test asserts zero network calls
First-turn recall—✗ 5-turn extraction lag — early recalls return nothing—✓ turn-by-turn extraction with an invocation trigger works from the first exchange
Failure blast radius✗ sync client blocks the event loop✗ errors surface as unhandled AggregateMemoryError—✓ search and extraction fail open; only explicit add() raises
Model-facing danger✗ exposes a `delete` action — prompt injection wipes memories——✓ search + save only; identity never model-facing
Data at rest✗ default FAISS in /tmp — wiped on restartcloud—✓ MemorySync cloud
Framework pin—✗ strands-agents>=1.45—✓ zero dependencies
Python floor—✗ 3.11 only—✓ 3.10 (matches the framework)

Where to go next

Was this page helpful?