Skip to content

Commit 2d88035

Browse files
committed
Create MongoDB chat memory implementation
Signed-off-by: Łukasz Jernaś <[email protected]>
1 parent fbec267 commit 2d88035

File tree

13 files changed

+688
-0
lines changed

13 files changed

+688
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xmlns="http://maven.apache.org/POM/4.0.0"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
<parent>
7+
<groupId>org.springframework.ai</groupId>
8+
<artifactId>spring-ai-parent</artifactId>
9+
<version>1.0.0-SNAPSHOT</version>
10+
<relativePath>../../../../../pom.xml</relativePath>
11+
</parent>
12+
<artifactId>spring-ai-autoconfigure-model-chat-memory-mongodb</artifactId>
13+
<packaging>jar</packaging>
14+
<name>Spring AI MongoDB Chat Memory Auto Configuration</name>
15+
<description>Spring AI MongoDB Chat Memory Auto Configuration</description>
16+
<url>https://github.com/spring-projects/spring-ai</url>
17+
18+
<scm>
19+
<url>https://github.com/spring-projects/spring-ai</url>
20+
<connection>git://github.com/spring-projects/spring-ai.git</connection>
21+
<developerConnection>[email protected]:spring-projects/spring-ai.git</developerConnection>
22+
</scm>
23+
24+
25+
<dependencies>
26+
27+
<dependency>
28+
<groupId>org.springframework.ai</groupId>
29+
<artifactId>spring-ai-model-chat-memory-mongodb</artifactId>
30+
<version>${project.parent.version}</version>
31+
</dependency>
32+
33+
<!-- Boot dependencies -->
34+
<dependency>
35+
<groupId>org.springframework.boot</groupId>
36+
<artifactId>spring-boot-starter</artifactId>
37+
</dependency>
38+
39+
<dependency>
40+
<groupId>org.springframework.boot</groupId>
41+
<artifactId>spring-boot-starter-data-mongodb</artifactId>
42+
</dependency>
43+
44+
<dependency>
45+
<groupId>org.springframework.boot</groupId>
46+
<artifactId>spring-boot-configuration-processor</artifactId>
47+
<optional>true</optional>
48+
</dependency>
49+
50+
<dependency>
51+
<groupId>org.springframework.boot</groupId>
52+
<artifactId>spring-boot-autoconfigure-processor</artifactId>
53+
<optional>true</optional>
54+
</dependency>
55+
56+
<dependency>
57+
<groupId>org.mongodb</groupId>
58+
<artifactId>mongodb-driver-sync</artifactId>
59+
</dependency>
60+
61+
<!-- Test dependencies -->
62+
<dependency>
63+
<groupId>org.springframework.ai</groupId>
64+
<artifactId>spring-ai-test</artifactId>
65+
<version>${project.parent.version}</version>
66+
<scope>test</scope>
67+
</dependency>
68+
69+
<dependency>
70+
<groupId>org.springframework.ai</groupId>
71+
<artifactId>spring-ai-autoconfigure-model-chat-client</artifactId>
72+
<version>${project.parent.version}</version>
73+
<scope>test</scope>
74+
</dependency>
75+
76+
<dependency>
77+
<groupId>org.springframework.ai</groupId>
78+
<artifactId>spring-ai-openai</artifactId>
79+
<version>${project.parent.version}</version>
80+
<scope>test</scope>
81+
</dependency>
82+
83+
<dependency>
84+
<groupId>org.springframework.boot</groupId>
85+
<artifactId>spring-boot-starter-test</artifactId>
86+
<scope>test</scope>
87+
</dependency>
88+
89+
<dependency>
90+
<groupId>org.springframework.boot</groupId>
91+
<artifactId>spring-boot-testcontainers</artifactId>
92+
<scope>test</scope>
93+
</dependency>
94+
95+
<dependency>
96+
<groupId>org.testcontainers</groupId>
97+
<artifactId>junit-jupiter</artifactId>
98+
<scope>test</scope>
99+
</dependency>
100+
101+
<dependency>
102+
<groupId>org.testcontainers</groupId>
103+
<artifactId>mongodb</artifactId>
104+
<scope>test</scope>
105+
</dependency>
106+
107+
<dependency>
108+
<groupId>org.mockito</groupId>
109+
<artifactId>mockito-core</artifactId>
110+
<scope>test</scope>
111+
</dependency>
112+
</dependencies>
113+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2025-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.model.chat.memory.mongodb.autoconfigure;
18+
19+
import org.springframework.ai.chat.memory.mongodb.MongoDbChatMemory;
20+
import org.springframework.ai.chat.memory.mongodb.MongoDbChatMemoryConfig;
21+
import org.springframework.boot.autoconfigure.AutoConfiguration;
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
23+
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
24+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
25+
import org.springframework.context.annotation.Bean;
26+
import org.springframework.data.mongodb.core.MongoTemplate;
27+
28+
/**
29+
* Spring Boot auto-configuration for {@link MongoDbChatMemory}.
30+
*
31+
* @author Łukasz Jernaś
32+
* @since 1.0.0
33+
*/
34+
@AutoConfiguration(after = MongoAutoConfiguration.class)
35+
@EnableConfigurationProperties(MongoDbChatMemoryProperties.class)
36+
public class MongoDbChatMemoryAutoConfiguration {
37+
38+
@Bean
39+
@ConditionalOnMissingBean
40+
public MongoDbChatMemory chatMemory(MongoDbChatMemoryProperties properties, MongoTemplate mongoTemplate) {
41+
var config = MongoDbChatMemoryConfig.builder().withTemplate(mongoTemplate).build();
42+
return new MongoDbChatMemory(config);
43+
}
44+
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2025-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.model.chat.memory.mongodb.autoconfigure;
18+
19+
import org.springframework.boot.context.properties.ConfigurationProperties;
20+
21+
import java.time.Duration;
22+
23+
@ConfigurationProperties(MongoDbChatMemoryProperties.CONFIG_PREFIX)
24+
public record MongoDbChatMemoryProperties(Duration ttl) {
25+
26+
public static final String CONFIG_PREFIX = "spring.ai.chat.memory.mongodb";
27+
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#
2+
# Copyright 2024-2025 the original author or authors.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# https://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
org.springframework.ai.model.chat.memory.mongodb.autoconfigure.MongoDbChatMemoryAutoConfiguration
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package org.springframework.ai.model.chat.memory.mongodb.autoconfigure;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.springframework.ai.chat.memory.mongodb.MongoDbChatMemory;
5+
import org.springframework.ai.chat.messages.AssistantMessage;
6+
import org.springframework.ai.chat.messages.Message;
7+
import org.springframework.ai.chat.messages.SystemMessage;
8+
import org.springframework.ai.chat.messages.UserMessage;
9+
import org.springframework.boot.autoconfigure.AutoConfigurations;
10+
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
11+
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
12+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
13+
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
14+
import org.testcontainers.containers.MongoDBContainer;
15+
import org.testcontainers.junit.jupiter.Container;
16+
import org.testcontainers.junit.jupiter.Testcontainers;
17+
18+
import java.util.List;
19+
import java.util.UUID;
20+
21+
import static org.assertj.core.api.Assertions.assertThat;
22+
23+
@Testcontainers
24+
class MongoDbChatMemoryAutoConfigurationIT {
25+
26+
@Container
27+
@ServiceConnection
28+
static MongoDBContainer mongoDbContainer = new MongoDBContainer("mongo");
29+
30+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
31+
.withConfiguration(AutoConfigurations.of(MongoDbChatMemoryAutoConfiguration.class, MongoAutoConfiguration.class,
32+
MongoDataAutoConfiguration.class))
33+
.withPropertyValues(
34+
String.format("spring.data.mongodb.uri=%s/ai_test", mongoDbContainer.getConnectionString()));
35+
36+
@Test
37+
void mongodbChatMemoryBean_exists() {
38+
this.contextRunner.run(context -> assertThat(context.containsBean("chatMemory")).isTrue());
39+
}
40+
41+
@Test
42+
void allMethods_shouldExecute() {
43+
this.contextRunner.run(context -> {
44+
var chatMemory = context.getBean(MongoDbChatMemory.class);
45+
var conversationId = UUID.randomUUID().toString();
46+
var systemMessage = new SystemMessage("Some system message");
47+
48+
chatMemory.add(conversationId, systemMessage);
49+
50+
assertThat(chatMemory.get(conversationId, Integer.MAX_VALUE)).hasSize(1);
51+
assertThat(chatMemory.get(conversationId, Integer.MAX_VALUE)).isEqualTo(List.of(systemMessage));
52+
53+
chatMemory.clear(conversationId);
54+
55+
assertThat(chatMemory.get(conversationId, Integer.MAX_VALUE)).isEmpty();
56+
57+
var multipleMessages = List.<Message>of(new UserMessage("Message from the user 1"),
58+
new AssistantMessage("Message from the assistant 1"));
59+
60+
chatMemory.add(conversationId, multipleMessages);
61+
62+
assertThat(chatMemory.get(conversationId, Integer.MAX_VALUE)).hasSize(multipleMessages.size());
63+
assertThat(chatMemory.get(conversationId, Integer.MAX_VALUE)).isEqualTo(multipleMessages);
64+
});
65+
}
66+
67+
}

Diff for: memory/spring-ai-model-chat-memory-mongodb/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[Chat Memory Documentation](https://docs.spring.io/spring-ai/reference/api/chatclient.html#_chat_memory)

Diff for: memory/spring-ai-model-chat-memory-mongodb/pom.xml

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2023-2024 the original author or authors.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ https://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
18+
<project xmlns="http://maven.apache.org/POM/4.0.0"
19+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
21+
<modelVersion>4.0.0</modelVersion>
22+
<parent>
23+
<groupId>org.springframework.ai</groupId>
24+
<artifactId>spring-ai-parent</artifactId>
25+
<version>1.0.0-SNAPSHOT</version>
26+
<relativePath>../../pom.xml</relativePath>
27+
</parent>
28+
29+
<artifactId>spring-ai-model-chat-memory-mongodb</artifactId>
30+
<name>Spring AI MongoDB Chat Memory</name>
31+
<description>Spring AI MongoDB Chat Memory implementation</description>
32+
33+
<dependencies>
34+
<dependency>
35+
<groupId>org.springframework.ai</groupId>
36+
<artifactId>spring-ai-client-chat</artifactId>
37+
<version>${project.version}</version>
38+
</dependency>
39+
40+
<!-- MongoDB -->
41+
<dependency>
42+
<groupId>org.springframework.data</groupId>
43+
<artifactId>spring-data-mongodb</artifactId>
44+
</dependency>
45+
46+
<dependency>
47+
<groupId>org.mongodb</groupId>
48+
<artifactId>mongodb-driver-sync</artifactId>
49+
</dependency>
50+
51+
<dependency>
52+
<groupId>org.springframework.boot</groupId>
53+
<artifactId>spring-boot-starter-test</artifactId>
54+
<scope>test</scope>
55+
</dependency>
56+
57+
<dependency>
58+
<groupId>org.springframework.ai</groupId>
59+
<artifactId>spring-ai-test</artifactId>
60+
<version>${project.version}</version>
61+
<scope>test</scope>
62+
</dependency>
63+
64+
<dependency>
65+
<groupId>org.springframework.boot</groupId>
66+
<artifactId>spring-boot-testcontainers</artifactId>
67+
<scope>test</scope>
68+
</dependency>
69+
70+
<dependency>
71+
<groupId>org.testcontainers</groupId>
72+
<artifactId>mongodb</artifactId>
73+
<scope>test</scope>
74+
</dependency>
75+
76+
<dependency>
77+
<groupId>org.testcontainers</groupId>
78+
<artifactId>junit-jupiter</artifactId>
79+
<scope>test</scope>
80+
</dependency>
81+
82+
</dependencies>
83+
84+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2024-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.chat.memory.mongodb;
18+
19+
import org.springframework.data.mongodb.core.index.Indexed;
20+
import org.springframework.data.mongodb.core.mapping.Document;
21+
22+
import java.time.Instant;
23+
24+
@Document("ai_chat_memory")
25+
public record Conversation(@Indexed String conversationId, Message message, Instant timestamp) {
26+
public record Message(String content, String type) {
27+
}
28+
}

0 commit comments

Comments
 (0)