diff --git a/auto-configurations/models/chat/memory/spring-ai-autoconfigure-model-chat-memory-cassandra/pom.xml b/auto-configurations/models/chat/memory/spring-ai-autoconfigure-model-chat-memory-cassandra/pom.xml index ce15195db..5b34671b7 100644 --- a/auto-configurations/models/chat/memory/spring-ai-autoconfigure-model-chat-memory-cassandra/pom.xml +++ b/auto-configurations/models/chat/memory/spring-ai-autoconfigure-model-chat-memory-cassandra/pom.xml @@ -32,7 +32,7 @@ org.springframework.ai - spring-ai-cassandra-store + spring-ai-model-chat-memory-cassandra ${project.parent.version} diff --git a/memory/spring-ai-model-chat-memory-cassandra/pom.xml b/memory/spring-ai-model-chat-memory-cassandra/pom.xml new file mode 100644 index 000000000..cfdd6b944 --- /dev/null +++ b/memory/spring-ai-model-chat-memory-cassandra/pom.xml @@ -0,0 +1,78 @@ + + + + + 4.0.0 + + org.springframework.ai + spring-ai + 1.0.0-SNAPSHOT + ../../pom.xml + + + spring-ai-model-chat-memory-cassandra + Spring AI Cassandra Chat Memory + Spring AI Cassandra Chat Memory implementation + + + + org.springframework.ai + spring-ai-client-chat + ${project.version} + + + + org.apache.cassandra + java-driver-query-builder + + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.springframework.ai + spring-ai-test + ${project.version} + test + + + + org.springframework.boot + spring-boot-testcontainers + test + + + + org.testcontainers + cassandra + test + + + + org.testcontainers + junit-jupiter + test + + + + + diff --git a/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemory.java b/memory/spring-ai-model-chat-memory-cassandra/src/main/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemory.java similarity index 100% rename from vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemory.java rename to memory/spring-ai-model-chat-memory-cassandra/src/main/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemory.java diff --git a/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemoryConfig.java b/memory/spring-ai-model-chat-memory-cassandra/src/main/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemoryConfig.java similarity index 99% rename from vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemoryConfig.java rename to memory/spring-ai-model-chat-memory-cassandra/src/main/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemoryConfig.java index fa62afe59..6b7b1cf91 100644 --- a/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemoryConfig.java +++ b/memory/spring-ai-model-chat-memory-cassandra/src/main/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemoryConfig.java @@ -43,8 +43,6 @@ import com.datastax.oss.driver.shaded.guava.common.base.Preconditions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ai.cassandra.SchemaUtil; - /** * Configuration for the Cassandra Chat Memory store. * diff --git a/memory/spring-ai-model-chat-memory-cassandra/src/main/java/org/springframework/ai/chat/memory/cassandra/SchemaUtil.java b/memory/spring-ai-model-chat-memory-cassandra/src/main/java/org/springframework/ai/chat/memory/cassandra/SchemaUtil.java new file mode 100644 index 000000000..eeb1f5a15 --- /dev/null +++ b/memory/spring-ai-model-chat-memory-cassandra/src/main/java/org/springframework/ai/chat/memory/cassandra/SchemaUtil.java @@ -0,0 +1,69 @@ +/* + * Copyright 2025-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.chat.memory.cassandra; + +import java.time.Duration; + +import com.datastax.oss.driver.api.core.CqlSession; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.driver.api.querybuilder.SchemaBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Utility class for working with Cassandra schema. + * + * @author Mick Semb Wever + * @since 1.0.0 + */ +public final class SchemaUtil { + + private static final Logger logger = LoggerFactory.getLogger(SchemaUtil.class); + + private SchemaUtil() { + + } + + public static void checkSchemaAgreement(CqlSession session) throws IllegalStateException { + if (!session.checkSchemaAgreement()) { + logger.warn("Waiting for cluster schema agreement, sleeping 10s…"); + try { + Thread.sleep(Duration.ofSeconds(10).toMillis()); + } + catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(ex); + } + if (!session.checkSchemaAgreement()) { + logger.error("no cluster schema agreement still, continuing, let's hope this works…"); + } + } + } + + public static void ensureKeyspaceExists(CqlSession session, String keyspaceName) { + if (session.getMetadata().getKeyspace(keyspaceName).isEmpty()) { + SimpleStatement keyspaceStmt = SchemaBuilder.createKeyspace(keyspaceName) + .ifNotExists() + .withSimpleStrategy(1) + .build(); + + logger.debug("Executing {}", keyspaceStmt.getQuery()); + session.execute(keyspaceStmt); + } + } + +} diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemoryIT.java b/memory/spring-ai-model-chat-memory-cassandra/src/test/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemoryIT.java similarity index 98% rename from vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemoryIT.java rename to memory/spring-ai-model-chat-memory-cassandra/src/test/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemoryIT.java index 50a2180c1..c4cf7a8ee 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemoryIT.java +++ b/memory/spring-ai-model-chat-memory-cassandra/src/test/java/org/springframework/ai/chat/memory/cassandra/CassandraChatMemoryIT.java @@ -26,7 +26,6 @@ import org.testcontainers.containers.CassandraContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import org.springframework.ai.cassandra.CassandraImage; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/cassandra/CassandraImage.java b/memory/spring-ai-model-chat-memory-cassandra/src/test/java/org/springframework/ai/chat/memory/cassandra/CassandraImage.java similarity index 94% rename from vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/cassandra/CassandraImage.java rename to memory/spring-ai-model-chat-memory-cassandra/src/test/java/org/springframework/ai/chat/memory/cassandra/CassandraImage.java index ae9d8ec0e..ec3c76604 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/cassandra/CassandraImage.java +++ b/memory/spring-ai-model-chat-memory-cassandra/src/test/java/org/springframework/ai/chat/memory/cassandra/CassandraImage.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.cassandra; +package org.springframework.ai.chat.memory.cassandra; import org.testcontainers.utility.DockerImageName; diff --git a/pom.xml b/pom.xml index 42f887542..71a013be6 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,9 @@ spring-ai-rag advisors/spring-ai-advisors-vector-store + memory/spring-ai-model-chat-memory-neo4j + memory/spring-ai-model-chat-memory-cassandra + auto-configurations/common/spring-ai-autoconfigure-retry auto-configurations/models/tool/spring-ai-autoconfigure-model-tool @@ -49,8 +52,6 @@ auto-configurations/models/chat/memory/spring-ai-autoconfigure-model-chat-memory-cassandra auto-configurations/models/chat/memory/spring-ai-autoconfigure-model-chat-memory-neo4j - memory/spring-ai-model-chat-memory-neo4j - auto-configurations/models/chat/observation/spring-ai-autoconfigure-model-chat-observation auto-configurations/models/embedding/observation/spring-ai-autoconfigure-model-embedding-observation diff --git a/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStore.java b/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStore.java index 2c7e82753..902d42036 100644 --- a/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStore.java +++ b/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStore.java @@ -64,7 +64,6 @@ import com.datastax.oss.driver.shaded.guava.common.base.Preconditions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.ai.cassandra.SchemaUtil; import org.springframework.ai.document.Document; import org.springframework.ai.document.DocumentMetadata; import org.springframework.ai.embedding.EmbeddingModel; diff --git a/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/cassandra/SchemaUtil.java b/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/SchemaUtil.java similarity index 97% rename from vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/cassandra/SchemaUtil.java rename to vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/SchemaUtil.java index ebaf90de2..caf10a02e 100644 --- a/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/cassandra/SchemaUtil.java +++ b/vector-stores/spring-ai-cassandra-store/src/main/java/org/springframework/ai/vectorstore/cassandra/SchemaUtil.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.ai.cassandra; +package org.springframework.ai.vectorstore.cassandra; import java.time.Duration; diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraImage.java b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraImage.java new file mode 100644 index 000000000..2a8bf1767 --- /dev/null +++ b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraImage.java @@ -0,0 +1,32 @@ +/* + * Copyright 2023-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ai.vectorstore.cassandra; + +import org.testcontainers.utility.DockerImageName; + +/** + * @author Thomas Vitale + */ +public final class CassandraImage { + + public static final DockerImageName DEFAULT_IMAGE = DockerImageName.parse("cassandra:5.0"); + + private CassandraImage() { + + } + +} diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraRichSchemaVectorStoreIT.java b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraRichSchemaVectorStoreIT.java index e85a844c0..dc62c874c 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraRichSchemaVectorStoreIT.java +++ b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraRichSchemaVectorStoreIT.java @@ -42,7 +42,6 @@ import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import org.testcontainers.shaded.org.apache.commons.lang3.RandomStringUtils; -import org.springframework.ai.cassandra.CassandraImage; import org.springframework.ai.document.Document; import org.springframework.ai.document.DocumentMetadata; import org.springframework.ai.embedding.EmbeddingModel; diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java index dc12de5a1..5da707e4d 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java +++ b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreIT.java @@ -38,7 +38,6 @@ import org.testcontainers.containers.CassandraContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import org.springframework.ai.cassandra.CassandraImage; import org.springframework.ai.document.Document; import org.springframework.ai.document.DocumentMetadata; import org.springframework.ai.embedding.EmbeddingModel; diff --git a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreObservationIT.java b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreObservationIT.java index 101a34782..21f5e9ddd 100644 --- a/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreObservationIT.java +++ b/vector-stores/spring-ai-cassandra-store/src/test/java/org/springframework/ai/vectorstore/cassandra/CassandraVectorStoreObservationIT.java @@ -32,7 +32,6 @@ import org.testcontainers.containers.CassandraContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; -import org.springframework.ai.cassandra.CassandraImage; import org.springframework.ai.document.Document; import org.springframework.ai.embedding.EmbeddingModel; import org.springframework.ai.embedding.TokenCountBatchingStrategy;