Spring AI Chat Memory with Infinispan

What You Will Learn

How to use Infinispan as a Spring AI ChatMemoryRepository to persist chat conversations. Messages are stored in an indexed Infinispan cache, supporting retrieval by conversation ID, listing all conversations, and deletion.

Prerequisites

  • Java 17+

  • Docker or Podman (optional)

You can start an Infinispan Server manually with Docker or Podman:

docker run -it --rm -p 11222:11222 -e USER=admin -e PASS=password quay.io/infinispan/server:latest
Tip
You can replace docker with podman in the command above if you use Podman.
Tip
If no server is running on localhost:11222, the application automatically starts an Infinispan container using Testcontainers.

Step 1: Add Dependencies

Add the Infinispan Spring AI chat memory repository auto-configuration:

<dependency>
   <groupId>org.infinispan</groupId>
   <artifactId>spring-ai-autoconfigure-model-chat-memory-repository-infinispan</artifactId>
</dependency>
<dependency>
   <groupId>org.infinispan</groupId>
   <artifactId>spring-ai-model-chat-memory-repository-infinispan</artifactId>
</dependency>

The auto-configuration creates the ChatMemoryRepository bean, registers the Protobuf schema, and creates the indexed cache automatically.

Step 2: Configure the Connection

In application.properties, configure the Infinispan connection:

infinispan.remote.server-list=127.0.0.1:11222
infinispan.remote.auth-username=admin
infinispan.remote.auth-password=password

Step 3: Save Messages

Inject the ChatMemoryRepository and save user and assistant messages to a conversation:

   @PostMapping(path = "/conversations/{conversationId}")
   public String addMessages(@PathVariable String conversationId,
         @RequestParam String userMessage,
         @RequestParam String assistantMessage) {
      List<Message> messages = List.of(
            new UserMessage(userMessage),
            AssistantMessage.builder().content(assistantMessage).build());
      chatMemoryRepository.saveAll(conversationId, messages);
      return "Saved " + messages.size() + " messages to conversation " + conversationId;
   }

Step 4: Retrieve Conversations

List all conversation IDs or retrieve all messages for a specific conversation:

   @GetMapping(path = "/conversations")
   public List<String> listConversations() {
      return chatMemoryRepository.findConversationIds();
   }

   @GetMapping(path = "/conversations/{conversationId}")
   public List<MessageResponse> getConversation(@PathVariable String conversationId) {
      return chatMemoryRepository.findByConversationId(conversationId).stream()
            .map(m -> new MessageResponse(m.getMessageType().name(), m.getText()))
            .toList();
   }

Step 5: Delete Conversations

Remove all messages for a conversation:

   @DeleteMapping(path = "/conversations/{conversationId}")
   public String deleteConversation(@PathVariable String conversationId) {
      chatMemoryRepository.deleteByConversationId(conversationId);
      return "Deleted conversation " + conversationId;
   }

Step 6: Run the Tutorial

mvn spring-boot:run

Then interact with the REST API:

curl -X POST "http://localhost:8080/conversations/chat-1?userMessage=What+is+Infinispan&assistantMessage=A+distributed+data+store"
curl http://localhost:8080/conversations
curl http://localhost:8080/conversations/chat-1
curl -X DELETE http://localhost:8080/conversations/chat-1

What’s Next