Skip to content

Commit 9895b6d

Browse files
committed
Modularise Spring AI Spring Boot autoconfigurations
- Split spring-ai-spring-boot-autoconfigure into modules - This PR addresses the restructuring of the following spring boot autoconfigurations: - spring-ai retry -> common - spring-ai chat client/model/memory -> chat - spring-ai chat/embedding/image observation -> observation - spring-ai chat/embedding models -> models - Update the Spring AI BOM and boot starters with the new autoconfigure modules Signed-off-by: Ilayaperumal Gopinathan <[email protected]>
1 parent 413ab96 commit 9895b6d

File tree

295 files changed

+23039
-50
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

295 files changed

+23039
-50
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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</artifactId>
9+
<version>1.0.0-SNAPSHOT</version>
10+
<relativePath>../../../pom.xml</relativePath>
11+
</parent>
12+
<artifactId>spring-ai-chat-client-spring-boot-autoconfigure</artifactId>
13+
<packaging>jar</packaging>
14+
<name>Spring AI Chat Client Auto Configuration</name>
15+
<description>Spring AI Chat Client 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-core</artifactId>
30+
<version>${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-configuration-processor</artifactId>
42+
<optional>true</optional>
43+
</dependency>
44+
45+
<!-- Test dependencies -->
46+
<dependency>
47+
<groupId>org.springframework.ai</groupId>
48+
<artifactId>spring-ai-test</artifactId>
49+
<version>${project.parent.version}</version>
50+
<scope>test</scope>
51+
</dependency>
52+
53+
<dependency>
54+
<groupId>org.springframework.boot</groupId>
55+
<artifactId>spring-boot-starter-test</artifactId>
56+
<scope>test</scope>
57+
</dependency>
58+
59+
<dependency>
60+
<groupId>org.mockito</groupId>
61+
<artifactId>mockito-core</artifactId>
62+
<scope>test</scope>
63+
</dependency>
64+
</dependencies>
65+
66+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright 2023-2024 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.autoconfigure.chat.client;
18+
19+
import io.micrometer.observation.ObservationRegistry;
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
22+
23+
import org.springframework.ai.chat.client.ChatClient;
24+
import org.springframework.ai.chat.client.ChatClientCustomizer;
25+
import org.springframework.ai.chat.client.observation.ChatClientInputContentObservationFilter;
26+
import org.springframework.ai.chat.client.observation.ChatClientObservationConvention;
27+
import org.springframework.ai.chat.model.ChatModel;
28+
import org.springframework.beans.factory.ObjectProvider;
29+
import org.springframework.boot.autoconfigure.AutoConfiguration;
30+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
31+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
32+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
33+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
34+
import org.springframework.boot.context.properties.EnableConfigurationProperties;
35+
import org.springframework.context.annotation.Bean;
36+
import org.springframework.context.annotation.Scope;
37+
38+
/**
39+
* {@link EnableAutoConfiguration Auto-configuration} for {@link ChatClient}.
40+
* <p>
41+
* This will produce a {@link ChatClient.Builder ChatClient.Builder} bean with the
42+
* {@code prototype} scope, meaning each injection point will receive a newly cloned
43+
* instance of the builder.
44+
*
45+
* @author Christian Tzolov
46+
* @author Mark Pollack
47+
* @author Josh Long
48+
* @author Arjen Poutsma
49+
* @author Thomas Vitale
50+
* @since 1.0.0
51+
*/
52+
@AutoConfiguration
53+
@ConditionalOnClass(ChatClient.class)
54+
@EnableConfigurationProperties(ChatClientBuilderProperties.class)
55+
@ConditionalOnProperty(prefix = ChatClientBuilderProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true",
56+
matchIfMissing = true)
57+
public class ChatClientAutoConfiguration {
58+
59+
private static final Logger logger = LoggerFactory.getLogger(ChatClientAutoConfiguration.class);
60+
61+
@Bean
62+
@ConditionalOnMissingBean
63+
ChatClientBuilderConfigurer chatClientBuilderConfigurer(ObjectProvider<ChatClientCustomizer> customizerProvider) {
64+
ChatClientBuilderConfigurer configurer = new ChatClientBuilderConfigurer();
65+
configurer.setChatClientCustomizers(customizerProvider.orderedStream().toList());
66+
return configurer;
67+
}
68+
69+
@Bean
70+
@Scope("prototype")
71+
@ConditionalOnMissingBean
72+
ChatClient.Builder chatClientBuilder(ChatClientBuilderConfigurer chatClientBuilderConfigurer, ChatModel chatModel,
73+
ObjectProvider<ObservationRegistry> observationRegistry,
74+
ObjectProvider<ChatClientObservationConvention> observationConvention) {
75+
76+
ChatClient.Builder builder = ChatClient.builder(chatModel,
77+
observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP),
78+
observationConvention.getIfUnique(() -> null));
79+
return chatClientBuilderConfigurer.configure(builder);
80+
}
81+
82+
@Bean
83+
@ConditionalOnMissingBean
84+
@ConditionalOnProperty(prefix = ChatClientBuilderProperties.CONFIG_PREFIX + ".observations", name = "include-input",
85+
havingValue = "true")
86+
ChatClientInputContentObservationFilter chatClientInputContentObservationFilter() {
87+
logger.warn(
88+
"You have enabled the inclusion of the input content in the observations, with the risk of exposing sensitive or private information. Please, be careful!");
89+
return new ChatClientInputContentObservationFilter();
90+
}
91+
92+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Copyright 2023-2024 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.autoconfigure.chat.client;
18+
19+
import java.util.List;
20+
21+
import org.springframework.ai.chat.client.ChatClient;
22+
import org.springframework.ai.chat.client.ChatClientCustomizer;
23+
24+
/**
25+
* Builder for configuring a {@link ChatClient.Builder}.
26+
*
27+
* @author Christian Tzolov
28+
* @author Mark Pollack
29+
* @author Josh Long
30+
* @author Arjen Poutsma
31+
* @since 1.0.0 M1
32+
*/
33+
public class ChatClientBuilderConfigurer {
34+
35+
private List<ChatClientCustomizer> customizers;
36+
37+
void setChatClientCustomizers(List<ChatClientCustomizer> customizers) {
38+
this.customizers = customizers;
39+
}
40+
41+
/**
42+
* Configure the specified {@link ChatClient.Builder}. The builder can be further
43+
* tuned and default settings can be overridden.
44+
* @param builder the {@link ChatClient.Builder} instance to configure
45+
* @return the configured builder
46+
*/
47+
public ChatClient.Builder configure(ChatClient.Builder builder) {
48+
applyCustomizers(builder);
49+
return builder;
50+
}
51+
52+
private void applyCustomizers(ChatClient.Builder builder) {
53+
if (this.customizers != null) {
54+
for (ChatClientCustomizer customizer : this.customizers) {
55+
customizer.customize(builder);
56+
}
57+
}
58+
}
59+
60+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2023-2024 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.autoconfigure.chat.client;
18+
19+
import org.springframework.boot.context.properties.ConfigurationProperties;
20+
21+
/**
22+
* Configuration properties for the chat client builder.
23+
*
24+
* @author Christian Tzolov
25+
* @author Mark Pollack
26+
* @author Josh Long
27+
* @author Arjen Poutsma
28+
* @since 1.0.0
29+
*/
30+
@ConfigurationProperties(ChatClientBuilderProperties.CONFIG_PREFIX)
31+
public class ChatClientBuilderProperties {
32+
33+
public static final String CONFIG_PREFIX = "spring.ai.chat.client";
34+
35+
/**
36+
* Enable chat client builder.
37+
*/
38+
private boolean enabled = true;
39+
40+
private Observations observations = new Observations();
41+
42+
public Observations getObservations() {
43+
return this.observations;
44+
}
45+
46+
public boolean isEnabled() {
47+
return this.enabled;
48+
}
49+
50+
public void setEnabled(boolean enabled) {
51+
this.enabled = enabled;
52+
}
53+
54+
public static class Observations {
55+
56+
/**
57+
* Whether to include the input content in the observations.
58+
*/
59+
private boolean includeInput = false;
60+
61+
public boolean isIncludeInput() {
62+
return this.includeInput;
63+
}
64+
65+
public void setIncludeInput(boolean includeCompletion) {
66+
this.includeInput = includeCompletion;
67+
}
68+
69+
}
70+
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
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+
org.springframework.ai.autoconfigure.chat.client.ChatClientAutoConfiguration
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2023-2024 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.autoconfigure.chat.client;
18+
19+
import org.junit.jupiter.api.Test;
20+
21+
import org.springframework.ai.chat.client.observation.ChatClientInputContentObservationFilter;
22+
import org.springframework.boot.autoconfigure.AutoConfigurations;
23+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
27+
/**
28+
* Unit tests for {@link ChatClientAutoConfiguration} observability support.
29+
*
30+
* @author Christian Tzolov
31+
*/
32+
class ChatClientObservationAutoConfigurationTests {
33+
34+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
35+
.withConfiguration(AutoConfigurations.of(ChatClientAutoConfiguration.class));
36+
37+
@Test
38+
void inputContentFilterDefault() {
39+
this.contextRunner
40+
.run(context -> assertThat(context).doesNotHaveBean(ChatClientInputContentObservationFilter.class));
41+
}
42+
43+
@Test
44+
void inputContentFilterEnabled() {
45+
this.contextRunner.withPropertyValues("spring.ai.chat.client.observations.include-input=true")
46+
.run(context -> assertThat(context).hasSingleBean(ChatClientInputContentObservationFilter.class));
47+
}
48+
49+
}

0 commit comments

Comments
 (0)