TL;DR
- A deployed agent recalls a returning user on its own. It writes every turn and injects the right past context before the model sees the prompt. This works once you attach a session manager with a retrieval config. With no retrieval config it writes and never reads. With no session manager it stays stateless.
- Recall survives the microVM boundary. I stated a preference in one Runtime session, and a different session on a different microVM answered an unrelated question with the exact email address and constraint, with no manual retrieval.
- Isolation is per-user by namespace. Three tenants shared one memory resource and each got only their own data. One tenant asking “how do you contact me” saw only their own email.
- The four long-term strategies do different jobs and fire at different speeds. Facts, preferences, and session summaries land in about a minute. Episodic records are completion-gated and took extraction plus consolidation of roughly half a minute, and only after the episode reached a natural conclusion.
- Long-term memory is eventually consistent. Extraction and consolidation run asynchronously after a turn is written, so a preference read moments after it changed can still return the old value until the update settles. Design for the delay.
A deployed agent’s session is a microVM that the platform tears down when the call ends. That is what makes Runtime scale. It also means the agent starts every conversation from nothing. A returning user re-introduces themselves every time. Everything the agent figured out last session is gone with the container.
The gap is structural. The model API is stateless — every call receives a context window and returns a response with no awareness of previous calls. The application layer has to reconstruct continuity. Amazon Bedrock AgentCore Memory is the managed version of that layer: a fully managed service that lets agents remember and recall across conversations, isolated per entity by namespace. It gives the agent a returning-user experience — it recognizes who is calling and picks up where the last conversation ended. It also composes across agents: TUI reported using Runtime to host agents and Memory to share context between them in production.
I wired it into the same two-tier support-triage agent I deployed to Runtime, and ran the full loop: write in one session, recall in another, across three separate users. This is what I found.
The two layers
Memory has two layers. Short-term is the raw conversation: every turn stored as an event, scoped by user and session. Long-term is the durable part. A strategy reads those events asynchronously and extracts something that outlives the session — a fact, a preference, a summary, an episode — retrievable later by semantic search.
Short-term is easy to prove. I wrote a fact in session one, then read it back through a fresh session object after the first was gone. It was there. The real question is whether the agent uses the long-term layer on its own, the way a returning-user experience works, without me hand-coding a retrieval call on every turn.
The agent recalls on its own — if you wire it to
The mechanism that makes recall automatic is a session manager the agent framework provides. Attached to the agent, it registers a hook that does two things on every turn: it persists the turn to memory, and — for each namespace in a retrieval config — it pulls the relevant records and injects them into the user message before the model sees it. The model reads the recalled context as if it were part of the prompt.
The config is small. Two parameters carry the behavior. The memory resource declares its strategies and how long raw events live. The retrieval config declares what the agent pulls back:
# 1. The memory resource: which strategies extract, and event retention.
create_memory(
name="support-memory",
eventExpiryDuration=7, # days raw short-term events persist
memoryStrategies=[
{"semanticMemoryStrategy": {"name": "facts",
"namespaces": ["/strategies/{memoryStrategyId}/actors/{actorId}/"]}},
{"userPreferenceMemoryStrategy": {"name": "prefs",
"namespaces": ["/prefs/{actorId}/"]}},
],
)
# 2. The agent side: actor + session scope the memory; retrieval_config turns
# on auto-injection. No retrieval_config = it writes but never recalls.
AgentCoreMemoryConfig(
memory_id=MEMORY_ID,
actor_id=user_id, # the tenant key — isolation happens here
session_id=session_id, # a distinct id is a distinct microVM
retrieval_config={
"/prefs/{actorId}/": RetrievalConfig(
top_k=3, relevance_score=0.1, strategy_id=PREF_STRATEGY_ID),
},
)
The {actorId} and {sessionId} templates in the namespaces carry the isolation and scoping. The platform substitutes the values at read and write time, so each user’s records land in their own namespace and are retrieved from it.
I tested it with a control. Three sessions, same model, same system prompt:
- Session A (memory on): the user states a preference — email only, never SMS, at a specific address.
- Session B (memory on, a new session): asked an unrelated question — “what contact details do you have on file, and how will you reach me?” The agent answered with the exact address and the never-SMS constraint. No manual retrieval, no re-statement.
- Session C (memory off, same model, same question): “I don’t have access to any customer account information on file.”
The specific email address is the discriminator. Only memory could supply it, and the control that lacked memory knew nothing. That gap makes the recall attributable to memory. Without it, the model would guess a generic “we’ll email you.”
One caveat: automatic recall is a wiring choice. With no session manager the agent stays stateless (Session C). With a session manager and no retrieval config it writes every turn and never injects. With a session manager and a retrieval config it writes and recalls. The platform supplies the mechanism. You decide the recall policy.
It survives the microVM boundary
Reading a fact back through a fresh object in the same process proves durability in the store. It does not prove durability across the boundary that matters. So I wired the session manager into the deployed agent — memory id passed as a runtime environment variable, the execution role granted the memory data-plane actions — and ran two Runtime sessions with different session ids.
Session one, microVM A: the user states “email me only at a specific address, never SMS, order ORD-991.” Session two used a different session id, so it ran on a different microVM: “what contact details do you have on file?” The agent answered with the exact address, that SMS was disabled, and the order number. It recalled all of it in a fresh microVM, with nothing carried over in process. A distinct session id is a distinct microVM, so recall across session ids is recall across microVMs. The statelessness that makes Runtime scale no longer costs the agent its memory.
Three tenants, one memory, no bleed
Per-user isolation is what makes this usable for anything real. One agent serves many users; each must see only their own memory. AgentCore keys long-term records by an actorId namespace, so I ran the whole loop as a multi-tenant test through the deployed agent.
Three tenants, each with a session-one conversation carrying different material: one an email preference and an order, one an SMS preference and a subscription tier, one a support issue. Then each, in a new session, asked something that would surface their own memory.
| Tenant | Recall answer | Own memory | Cross-tenant bleed |
|---|---|---|---|
| alice | ”Email: (her address), email only” | yes | none |
| bob | ”text/SMS at (his number), Pro tier” | yes | none |
| carol | ”502 error, resolved” | yes | none |
Each recalled only their own. Bob asked how he’d be contacted and got his number and plan. He never got alice’s email, even though both are contact preferences living in the same memory resource. That is actorId namespace isolation holding under a shared agent, measured in a running deployment. The strategies also extracted only what was present: carol stated no preference, so carol got no preference record. Nothing was invented to fill the slot.
Four strategies, four speeds
AgentCore has four long-term strategies. Each does a distinct job. Running them on one conversation showed they behave differently enough that treating them alike will burn you.
| Strategy | Job | Scope | Extract latency (observed) |
|---|---|---|---|
| Semantic | durable facts | per user | ~1 min |
| User preference | personalization | per user | ~1 min |
| Summarization | condense a session | per session | ~1 min |
| Episodic | learn from a completed interaction | per session | slow, completion-gated |
Semantic, preference, and summarization all extracted within about a minute. Summarization returned a compact record that condensed an eight-turn troubleshooting session down to what was tried, what failed, and what fixed it. It stored a summary in place of the transcript. The semantic strategy went further: it stored an inferred fact (“the user has a pending refund”) the user never literally said. Long-term memory stores extractions of the conversation, not copies of it.
Episodic is the slow one. The other three strategies extract while the conversation is still going. Episodic waits until the interaction is finished, because it records the whole episode as one unit — the situation, what the agent did, and how it turned out. The documentation says the system “waits to see if the conversation is continued” before deciding an episode is complete.
This tripped me up. I ran a support conversation that resolved a checkout error, then queried episodic a few minutes later. Nothing. The other three strategies had already stored their records. Episodic returned empty because, from the platform’s view, the conversation might not be over.
When I added a clear ending — the user says “the issue is resolved, you can close this ticket” — and waited longer, episodic produced two records. One episode: the customer hit a checkout error, the agent worked through it, and it was fixed. And one reflection, a reusable lesson pulled from that episode: “prioritize server-side diagnostics for payment errors that reproduce across browsers.” The reflection is the payoff — the next time a similar ticket comes in, the agent can retrieve that lesson instead of solving it from scratch.
The practical warning: episodic records land later than the others and only after the conversation ends. A retrieval loop tuned to semantic memory’s one-minute latency will query episodic too early, get nothing, and conclude it is broken.
You can read the whole loop in one trace
Memory operations are visible in the traces. With CloudWatch Transaction Search enabled, a single invocation produces one parented trace, and the memory operations appear as spans inside it, alongside the reasoning:
POST /invocations 6.96s
invoke_agent → chat (Haiku) 1.2s ← router turn
RetrieveMemoryRecords 0.2s ← auto-inject read
RetrieveMemoryRecords 0.2s
execute_event_loop_cycle → chat (Haiku) 4.5s ← the answer
CreateEvent 0.1s ← auto-persist write
The retrieve spans (the injection) fire before the model call. The create spans (the write) bracket it. The read-reason-write loop is legible with per-span latency, and the model tier is named in the span. When an agent recalls the wrong thing, this trace shows whether it was a bad retrieve, a missing extraction, or the model ignoring the context it was handed.
The extraction pipeline is metered too, and it explains the latency differences above. In the AWS/Bedrock-AgentCore namespace, Invocations breaks down by operation — CreateEvent (writes), RetrieveMemoryRecords (reads) — and, split by strategy, an Extraction phase followed by a Consolidation phase. That is the asynchronous work that turns raw events into durable records, and it runs on a model. The episodic strategy’s Consolidation carried InputTokenUsage and OutputTokenUsage, each phase on the order of ten-plus seconds against sub-second reads. The cost lands at extraction time as model-token work. A chatty agent with several strategies pays for the model that turns its transcripts into memories.
What’s missing: long-term memory is eventually consistent
Long-term memory extraction runs asynchronously. When a turn is written, the platform extracts and consolidates insights in the background, and the docs are explicit that “it may take a minute or more for insights from a new conversation to become available for retrieval”. The store is eventually consistent by design.
I saw the window directly. With “email only, never SMS” stored, I had the user reverse it — “actually, SMS is fine now, text me at this number” — and then read the preference back immediately. The semantic strategy had already replaced its record with the new contact fact; the preference strategy still returned the old value and converged only after a longer wait. That is the documented processing delay, and reading during it returns a stale value. An application has to account for the delay: use short-term memory for immediate needs, and treat a long-term memory as authoritative once it has settled.
So what
A deployed agent no longer starts from zero. Managed memory gives it automatic write, automatic recall across the microVM boundary, and per-user isolation strong enough to put many tenants behind one agent. The whole read-reason-write loop is visible in a trace. Wiring it is a config choice.
Durable memory has limits. The four strategies fire at different speeds. Episodic is completion-gated and slow enough to look broken. Long-term memory is eventually consistent, so a preference read moments after it changed can still return the old value. Use each strategy for what it is good at, use short-term memory for immediate needs, and treat a long-term memory as authoritative once it has settled.
The open thread I have not closed is read-time freshness. Extraction and consolidation run in the background, and at read time I do not have a signal for whether a given memory has settled or is still processing. Until I do, I would use short-term memory for anything an agent must act on within the same session it changed, and let long-term memory catch up in the background.
Part of a series working through Amazon Bedrock AgentCore by building on it. Start with The AgentCore Map for the full picture — Memory is the “what the agent remembers” organ in that map. See also AgentCore Runtime: Where an Agent Actually Runs, Two Ways to Authorize an Agent Tool, Who May Call What, and Two Things I Almost Called AgentCore Gaps.