AgentCore Memory
AgentCore Memory persists conversation turns and distils them into long-term memory records that are retrieved and injected as context before each user message. It is what lets the runtime remember a contact across separate invocations.
Implementation: libs/morpheus-llm/morpheus_llm/providers/base_service.py.
Provisioning: cdk/lib/stacks/agentcore-stack.ts (CfnMemory).
Strategies
Three strategies are configured, each writing to its own namespace:
| Strategy | Name | Namespace |
|---|---|---|
Semantic |
|
|
User preference |
|
|
Summary |
|
|
{actorId} and {sessionId} are resolved per invocation, so one contact’s facts are
never retrieved for another.
Retrieval configuration (_RETRIEVAL_CONFIG in base_service.py):
| Namespace | top_k |
Contents |
|---|---|---|
|
5 |
Extracted facts about the contact |
|
5 |
Stable preferences and contact details |
|
3 |
Summaries of earlier turns in this session |
Event expiry is 90 days (eventExpiryDuration: 90 on the CfnMemory resource).
How a session attaches
Memory is wired only when both a memory id and a session id are available:
def _make_session_manager(self, options: RunOptions):
if not self._memory_id or not options.session_id:
return None # run statelessly
actor_id = options.actor_id or options.session_id
memory_config = AgentCoreMemoryConfig(
memory_id=self._memory_id,
session_id=options.session_id,
actor_id=actor_id,
retrieval_config=_RETRIEVAL_CONFIG,
filter_restored_tool_context=True,
)
return AgentCoreMemorySessionManager(memory_config)
Returning None means the agent runs without memory rather than failing — which is
exactly what happens in the Lambda functions, where no memory resource is configured.
| Input | Source |
|---|---|
|
The |
|
|
|
|
filter_restored_tool_context=True strips restored tool-call context out of the
replayed conversation, so a resumed session does not re-present stale tool results as
if they were fresh.
Choosing an actorId
actorId is the memory partition key. It should be a stable identifier for the
person, so facts accumulate across sessions — a phone number in E.164, or a HubSpot
contact id. The dialler-agent workflow is invoked with the contact’s phone number as
actorId.
Omitting it falls back to session_id, which makes memory effectively
single-session: facts are written but can never be retrieved by a later invocation,
because the next session has a different id.
IAM
The runtime role is granted, scoped to the memory ARN:
bedrock-agentcore:CreateEvent
bedrock-agentcore:ListEvents
bedrock-agentcore:GetEvent
bedrock-agentcore:RetrieveMemoryRecords
bedrock-agentcore:ListMemoryRecords
bedrock-agentcore:GetMemory
The memory resource has its own execution role (MemoryExecutionRole) allowing
bedrock:InvokeModel — the extraction and summarisation strategies are themselves
model calls. See IAM.
Behaviour in the Lambda functions
The Lambdas use the same ClaudeAgentService, but they never set MEMORY_ID and
never pass a session_id, so _make_session_manager() returns None and every agent
call is stateless. This is intentional: enrichment, scoring, and email categorisation
are single-shot classifications with no conversation to remember.
Known inconsistency
agentcore/.bedrock_agentcore.yaml — the AgentCore CLI’s local configuration — has
memory.mode: NO_MEMORY and memory_id: null, while the CDK stack provisions a
memory resource and injects MEMORY_ID into the runtime. The deployed runtime uses
memory; a CLI-driven local run configured from that file does not. See
Development and container.