Introduction
In part 7, we explained how to add and use AgentCore short-term Memory to our application with the help of Spring AI AgentCore Memory. In this article, we'll use AgentCore long-term Memory instead.
We'll once again build on the spring-ai-2.0-ac-conference-app-agent-bedrock-agentcore-runtime sample application, which we introduced in part 6. Please review part 7 to better understand the base concept of Spring AI AgentCore Memory and how to add it to our application.
Create Bedrock AgentCore long-term Memory
I've written the article Amazon Bedrock AgentCore Runtime - Part 7 Using AgentCore long-term Memory with Strands Agents SDK about what AgentCore long-term Memory is and how to create one with the Python SDK. Also provided an example of how to use it with Strands Agent SDK. I refer to this article to understand the basics.
To run examples, we've already deployed our sample application on AgentCore Runtime by executing the RuntimeWithMCPStack stack in part 6. Next, let's create AgentCore long-term Memory with CDK for Java by executing the LongTermMemoryStack stack. First, let's look at what is happening there:
public class LongTermMemoryStack extends Stack {
public LongTermMemoryStack(Construct scope, String appName, StackProps stackProps) {
super(scope, id, stackProps);
var memory = Memory.Builder.create(this, "long-term-memory")
.memoryName("long_term_memory_for_conference_application")
.description("Long-Term Memory for Conference Application")
.expirationDuration(Duration.days(7))
.memoryStrategies(List.of(MemoryStrategy.usingBuiltInSummarization(),
MemoryStrategy.usingBuiltInSemantic()))
.build();
CfnOutput.Builder.create(this, "LongTermMemoryIdOutput").value(memory.getMemoryId()).build();
}
}
We use Bedrock AgentCore Memory.Builder to set the memory name, description, expiration duration, and then create the memory. By defining the memory strategies, we outline that we'll create the AgentCore long-term memory. We used the semantic and summarization built-in memory strategies. You can also set the currently supported user preference and episodic memory strategies instead. The MemoryStrategy class offers usingBuiltInUserPreference and usingBuiltInEpisodic methods for this purpose. You can also configure the Custom Memory Strategy.
You can deploy the stack with the command: cdk deploy spring-ai-ac-conference-application-lt-memory-stack -c awsAccountId={YOUR_AWS_ACCOUNT_ID}.
This is how the created long-term memory looks in the AgentCore Memory UI:
And this is how the default namespaces look:
If you're not satisfied with the built-in configuration, for example, default namespaces, you can set your own. Here is an example of how to create a semantic memory strategy:
MemoryStrategy.usingSemantic(ManagedStrategyProps.builder()
.name("name")
.namespaces(List.of("namespace1", "namespace2"))
.build());
Other memory strategies work the same; just use the corresponding using* method. But I always start with the built-in memory strategies.
Also, the Memory ID will be printed out, which we will need to configure in our Spring AI application. We can find the same Memory ID in the service UI above.
Finally, we need to configure the following IAM permissions to allow our application running on AgentCoreRuntime to access this AgentCore Memory:
{
"Sid": "BedrockAgentCoreLongTermMemory",
"Effect": "Allow",
"Action": [
"bedrock-agentcore:ListEvents",
"bedrock-agentcore:CreateEvent",
"bedrock-agentcore:RetrieveMemoryRecords",
"bedrock-agentcore:GetMemory"
],
"Resource": [
"arn:aws:bedrock-agentcore:{YOUR_AWS_REGION}:{YOUR_AWS_ACCOUNT_ID}:memory/{YOUR_LONG_TERM_MEMORY_ID}"
]
}
Configure Bedrock AgentCore long-term Memory in our sample application
To configure Bedrock AgentCore long-term Memory in our sample application, we need to make some changes to it. First, we need to configure some long-term memory-related properties in the application.properties:
agentcore.memory.memory-id={YOUR_LONG_TERM_MEMORY_ID}
agentcore.memory.long-term.auto-discovery=true
The first required property is the AgentCore Memory ID we just created. By setting agentcore.memory.long-term.auto-discovery to true, we use the recommended AgentCore long-term Memory autodiscovery option.
Autodiscovery behavior is:
- Queries AWS to discover all strategies configured in your memory
- Creates advisors only for supported types: SEMANTIC, SUMMARIZATION, USER_PREFERENCE, EPISODIC
- Skips CUSTOM strategy types (not supported by autodiscovery)
- Uses the first namespace if a strategy has multiple namespaces
- Uses default topK values for each strategy type
We can also override the specific settings for discovered strategies by providing explicit configuration. See the link above to find out how to do this. Another option is to use the AgentCore long-term Memory explicit configuration option, in which we need to specify each strategy manually.
Next, we need to ensure that we set ChatMemory to the ChatClient in the SpringAIAgentController. I'll provide the generic constructor, capable of dealing with no AgentCore Memory configured or short-term or long-term memory configured:
public SpringAIAgentController(ChatClient.Builder builder,
ChatMemory chatMemory, List<AgentCoreLongTermMemoryAdvisor> ltmAdvisors) {
var options = ToolCallingChatOptions.builder()
.model("us.anthropic.claude-sonnet-4-6")
.maxTokens(2000);
this.chatClient = builder.defaultOptions(options)
.defaultAdvisors(this.getAllMemoryAdvisors(chatMemory, ltmAdvisors))
.build())
.build();
....
}
private List<Advisor> getAllMemoryAdvisors(ChatMemory chatMemory, List<AgentCoreLongTermMemoryAdvisor> ltmAdvisors) {
Advisor chatMemoryAdvisor= MessageChatMemoryAdvisor.builder(chatMemory).build();
var cltmAdvisors=(List<Advisor>)(List<?>) ltmAdvisors;
var allAdvisors=new ArrayList<Advisor>();
allAdvisors.addAll(cltmAdvisors);
if(chatMemoryAdvisor!=null) {
allAdvisors.add(chatMemoryAdvisor);
}
return allAdvisors;
}
Short-term Spring AI AgentCore Memory implements the Spring AI ChatMemoryRepository interface. This doesn't work for long-term Spring AI AgentCore Memory. For this, we inject the list of AgentCoreLongTermMemoryAdvisor. Then we use the Advisors API to build the complete list of Advisors in the getAllMemoryAdvisors method. We use MessageChatMemoryAdvisor with the ChatMemory to build the short-term memory advisor, and then we add the long-term advisors to the list. We then provide this complete list of memory advisors as an input to the defaultAdvisors method of the ChatClient.Builder. Even if we don't configure the AgentCore short-term or long-term Memory (or both), the same code still works without throwing any exceptions. MessageChatMemoryAdvisor, and List of AgentCoreLongTermMemoryAdvisors or both will be null in such a case, which Spring AI treats the same way as not setting any advisors. That's all the changes we need to make to our application to use the AgentCore long-term memory.
The last step is exactly the same as for the short-term memory: to include a custom ChatMemory Conversation ID in the ChatClient. According to the documentation, ChatMemory.CONVERSATION_ID parameter is required for all memory advisors. Calls that omit this parameter will throw an IllegalArgumentException at runtime, as there is no default conversation ID.
The Spring AI AgentCore long-term Memory supports flexible conversation ID formats:
- Simple: user123 → actor: user123, session: default-session
- With Session: user123:session456 → actor: user123, session: session456
This is how the code looks for it in the SpringAIAgentController:
private final String CONVERSATION_ID="default-actor-id-12345678:default-session-id-12345678";
@AgentCoreInvocation
public Flux<String> invoceAsync(PromptRequest promptRequest, AgentCoreContext agentCoreContext) {
var token = getAuthTokenViaHttpClient();
...
var client = McpClient.async(getMcpClientTransport(token)).build();
client.initialize();
var asyncMcpToolCallbackProvider = AsyncMcpToolCallbackProvider.builder()
.mcpClients(client)
...
var content = this.chatClient.prompt()
.user(promptRequest.prompt())
.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, CONVERSATION_ID))
.tools(new DateTimeTools(),asyncMcpToolCallbackProvider.getToolCallbacks()).stream()
.content();
As shown above, we defined a static CONVERSATION_ID. However, if you'd like to use individual IDs depending on the actor or user providing the prompt, you can add the login functionality and set the individual user ID. Finally, we set the value of the conversation ID as the parameter of the memory advisor.
Then we need to rebuild the Docker image of our application and deploy it to the Amazon ECR. After it, we need to configure the correct ecrImageURI in the cdk.json. We covered those concepts in parts 2 and 4.
Finally, we need to redeploy the AgentCore Runtime stack with the command: cdk deploy spring-ai-ac-conference-application-agentcore-runtime-stack -c awsAccountId={YOUR_AWS_ACCOUNT_ID}.
Now, we can use the InvokeRuntimeAgent class to send prompts to our agent running on AgentCore Runtime. We described this in part 5 and can reuse these prompts to apply the talks to the conferences.
But now, similarly to the example of the short-term memory in part 7, we can ask such questions as: "You recently applied for some conferences for me. Can you provide me with the details?" The agent will give us a reply, which shows that it provided the answer using the AgentCore long-term Memory:
The reply is very similar to one provided in part 7 for the long-term memory.
Conclusion
In this article, we explained how to add and use AgentCore long-term Memory to our application with the help of Spring AI AgentCore Memory. In the next article, we'll add AgentCore Observability to our application.
If you like my content, please follow me on GitHub and give my repositories a star!
Please also check out my website for more technical content and upcoming public speaking activities.



Top comments (0)