Skip to content

Commit b44bcfd

Browse files
committed
Fixed Spring AOT support and regression issue introduced in spring-projectsGH-4751
PR spring-projects#4751 introduced a new error when using Spring AOT: ``` Exception in thread "main" org.springframework.beans.factory.aot.AotBeanProcessingException: Error processing bean with name 'org.springframework.ai.model.tool.autoconfigure.ToolCallingAutoConfiguration.toolcallbackprovider.mcp-excluded': instance supplier is not supported at org.springframework.beans.factory.aot.DefaultBeanRegistrationCodeFragments.getTarget(DefaultBeanRegistrationCodeFragments.java:82) at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.generateBeanDefinitionMethod(BeanDefinitionMethodGenerator.java:85) at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution$BeanDefinitionsRegistrationGenerator.generateBeanRegistration(BeanRegistrationsAotContribution.java:289) at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution$BeanDefinitionsRegistrationGenerator.lambda$generateRegisterBeanDefinitionMethods$0(BeanRegistrationsAotContribution.java:272) at java.base/java.lang.Iterable.forEach(Iterable.java:75) at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution$BeanDefinitionsRegistrationGenerator.generateRegisterBeanDefinitionMethods(BeanRegistrationsAotContribution.java:270) at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution$BeanDefinitionsRegistrationGenerator.generateBeanRegistrationsCode(BeanRegistrationsAotContribution.java:238) at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$generateBeanRegistrationClass$0(BeanRegistrationsAotContribution.java:116) ``` This PR fixes this issue by refactoring `ToolCallingAutoConfiguration` from using `BeanDefinitionRegistryPostProcessor` to `ObjectProvider` Signed-off-by: Dmitry Bedrin <[email protected]>
2 parents e54423b + a8d2208 commit b44bcfd

File tree

149 files changed

+5226
-3468
lines changed

Some content is hidden

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

149 files changed

+5226
-3468
lines changed

.github/workflows/continuous-integration.yml

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
name: CI/CD build
22

33
on:
4-
schedule:
5-
# Combined schedule covering both EST and CET working hours
6-
# Morning/Early builds
7-
- cron: '30 6 * * 1-5' # 7:30 AM CET / 1:30 AM EST
8-
- cron: '30 11 * * 1-5' # 12:30 PM CET / 6:30 AM EST
9-
# Midday builds
10-
- cron: '30 16 * * 1-5' # 7:30 PM CET / 11:30 AM EST
11-
# Afternoon/Evening builds
12-
- cron: '30 21 * * 1-5' # 10:30 PM CET / 4:30 PM EST
13-
workflow_dispatch:
4+
# DISABLED: Replaced by fast-continuous-integration.yml workflow
5+
# This workflow is kept for reference but will not run automatically
6+
# To re-enable, uncomment the schedule and workflow_dispatch sections below
7+
workflow_call: # Dummy trigger - workflow can only be called by other workflows (effectively disabled)
8+
# schedule:
9+
# # Combined schedule covering both EST and CET working hours
10+
# # Morning/Early builds
11+
# - cron: '30 6 * * 1-5' # 7:30 AM CET / 1:30 AM EST
12+
# - cron: '30 11 * * 1-5' # 12:30 PM CET / 6:30 AM EST
13+
# # Midday builds
14+
# - cron: '30 16 * * 1-5' # 7:30 PM CET / 11:30 AM EST
15+
# # Afternoon/Evening builds
16+
# - cron: '30 21 * * 1-5' # 10:30 PM CET / 4:30 PM EST
17+
# workflow_dispatch:
1418
# Note: If push triggers are added in the future, they should include:
1519
# push:
1620
# paths-ignore:

.github/workflows/fast-continuous-integration.yml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
name: Fast CI/CD build
22

33
on:
4+
schedule:
5+
# Combined schedule covering both EST and CET working hours
6+
# Morning/Early builds
7+
- cron: '30 6 * * 1-5' # 7:30 AM CET / 1:30 AM EST
8+
- cron: '30 11 * * 1-5' # 12:30 PM CET / 6:30 AM EST
9+
# Midday builds
10+
- cron: '30 16 * * 1-5' # 7:30 PM CET / 11:30 AM EST
11+
# Afternoon/Evening builds
12+
- cron: '30 21 * * 1-5' # 10:30 PM CET / 4:30 PM EST
413
workflow_dispatch:
5-
# Note: Schedule triggers commented out for initial testing
6-
# schedule:
7-
# - cron: '30 6 * * 1-5' # 7:30 AM CET / 1:30 AM EST
8-
# - cron: '30 11 * * 1-5' # 12:30 PM CET / 6:30 AM EST
9-
# - cron: '30 16 * * 1-5' # 7:30 PM CET / 11:30 AM EST
10-
# - cron: '30 21 * * 1-5' # 10:30 PM CET / 4:30 PM EST
1114

1215
jobs:
1316
build-all:

.github/workflows/main-push-fast.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
permissions:
2525
contents: read
2626
concurrency:
27-
group: ${{ github.workflow }}-${{ github.ref }}
27+
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.sha }}
2828
cancel-in-progress: true
2929
steps:
3030
- uses: actions/checkout@v4

.github/workflows/maintenance-fast.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
permissions:
1313
contents: read
1414
concurrency:
15-
group: ${{ github.workflow }}-${{ github.ref }}
15+
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.sha }}
1616
cancel-in-progress: true
1717
steps:
1818
- uses: actions/checkout@v4

advisors/spring-ai-advisors-vector-store/src/main/java/org/springframework/ai/chat/client/advisor/vectorstore/QuestionAnswerAdvisor.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,6 @@ public class QuestionAnswerAdvisor implements BaseAdvisor {
8383

8484
private final int order;
8585

86-
/**
87-
* Construct instance by given VectorStore
88-
* @param vectorStore the given VectorStore
89-
* @deprecated in favor of {@link #builder(VectorStore)}}
90-
*/
91-
@Deprecated
92-
public QuestionAnswerAdvisor(VectorStore vectorStore) {
93-
this(vectorStore, SearchRequest.builder().build(), DEFAULT_PROMPT_TEMPLATE, BaseAdvisor.DEFAULT_SCHEDULER,
94-
DEFAULT_ORDER);
95-
}
96-
9786
QuestionAnswerAdvisor(VectorStore vectorStore, SearchRequest searchRequest, @Nullable PromptTemplate promptTemplate,
9887
@Nullable Scheduler scheduler, int order) {
9988
Assert.notNull(vectorStore, "vectorStore cannot be null");

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-common/src/main/java/org/springframework/ai/mcp/client/common/autoconfigure/McpClientAutoConfiguration.java

Lines changed: 39 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,9 @@
2323
import io.modelcontextprotocol.client.McpClient;
2424
import io.modelcontextprotocol.client.McpSyncClient;
2525
import io.modelcontextprotocol.spec.McpSchema;
26-
import org.springaicommunity.mcp.method.changed.prompt.AsyncPromptListChangedSpecification;
27-
import org.springaicommunity.mcp.method.changed.prompt.SyncPromptListChangedSpecification;
28-
import org.springaicommunity.mcp.method.changed.resource.AsyncResourceListChangedSpecification;
29-
import org.springaicommunity.mcp.method.changed.resource.SyncResourceListChangedSpecification;
30-
import org.springaicommunity.mcp.method.changed.tool.AsyncToolListChangedSpecification;
31-
import org.springaicommunity.mcp.method.changed.tool.SyncToolListChangedSpecification;
32-
import org.springaicommunity.mcp.method.elicitation.AsyncElicitationSpecification;
33-
import org.springaicommunity.mcp.method.elicitation.SyncElicitationSpecification;
34-
import org.springaicommunity.mcp.method.logging.AsyncLoggingSpecification;
35-
import org.springaicommunity.mcp.method.logging.SyncLoggingSpecification;
36-
import org.springaicommunity.mcp.method.progress.AsyncProgressSpecification;
37-
import org.springaicommunity.mcp.method.progress.SyncProgressSpecification;
38-
import org.springaicommunity.mcp.method.sampling.AsyncSamplingSpecification;
39-
import org.springaicommunity.mcp.method.sampling.SyncSamplingSpecification;
40-
41-
import org.springframework.ai.mcp.client.common.autoconfigure.annotations.McpAsyncAnnotationCustomizer;
42-
import org.springframework.ai.mcp.client.common.autoconfigure.annotations.McpSyncAnnotationCustomizer;
26+
27+
import org.springframework.ai.mcp.annotation.spring.ClientMcpAsyncHandlersRegistry;
28+
import org.springframework.ai.mcp.annotation.spring.ClientMcpSyncHandlersRegistry;
4329
import org.springframework.ai.mcp.client.common.autoconfigure.configurer.McpAsyncClientConfigurer;
4430
import org.springframework.ai.mcp.client.common.autoconfigure.configurer.McpSyncClientConfigurer;
4531
import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpClientCommonProperties;
@@ -161,7 +147,8 @@ private String connectedClientName(String clientName, String serverConnectionNam
161147
matchIfMissing = true)
162148
public List<McpSyncClient> mcpSyncClients(McpSyncClientConfigurer mcpSyncClientConfigurer,
163149
McpClientCommonProperties commonProperties,
164-
ObjectProvider<List<NamedClientMcpTransport>> transportsProvider) {
150+
ObjectProvider<List<NamedClientMcpTransport>> transportsProvider,
151+
ClientMcpSyncHandlersRegistry clientMcpSyncHandlersRegistry) {
165152

166153
List<McpSyncClient> mcpSyncClients = new ArrayList<>();
167154

@@ -176,7 +163,22 @@ public List<McpSyncClient> mcpSyncClients(McpSyncClientConfigurer mcpSyncClientC
176163

177164
McpClient.SyncSpec spec = McpClient.sync(namedTransport.transport())
178165
.clientInfo(clientInfo)
179-
.requestTimeout(commonProperties.getRequestTimeout());
166+
.requestTimeout(commonProperties.getRequestTimeout())
167+
.sampling(samplingRequest -> clientMcpSyncHandlersRegistry.handleSampling(namedTransport.name(),
168+
samplingRequest))
169+
.elicitation(elicitationRequest -> clientMcpSyncHandlersRegistry
170+
.handleElicitation(namedTransport.name(), elicitationRequest))
171+
.loggingConsumer(loggingMessageNotification -> clientMcpSyncHandlersRegistry
172+
.handleLogging(namedTransport.name(), loggingMessageNotification))
173+
.progressConsumer(progressNotification -> clientMcpSyncHandlersRegistry
174+
.handleProgress(namedTransport.name(), progressNotification))
175+
.toolsChangeConsumer(newTools -> clientMcpSyncHandlersRegistry
176+
.handleToolListChanged(namedTransport.name(), newTools))
177+
.promptsChangeConsumer(newPrompts -> clientMcpSyncHandlersRegistry
178+
.handlePromptListChanged(namedTransport.name(), newPrompts))
179+
.resourcesChangeConsumer(newResources -> clientMcpSyncHandlersRegistry
180+
.handleResourceListChanged(namedTransport.name(), newResources))
181+
.capabilities(clientMcpSyncHandlersRegistry.getCapabilities(namedTransport.name()));
180182

181183
spec = mcpSyncClientConfigurer.configure(namedTransport.name(), spec);
182184

@@ -222,27 +224,14 @@ McpSyncClientConfigurer mcpSyncClientConfigurer(ObjectProvider<McpSyncClientCust
222224
return new McpSyncClientConfigurer(customizerProvider.orderedStream().toList());
223225
}
224226

225-
@Bean
226-
@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
227-
matchIfMissing = true)
228-
public McpSyncClientCustomizer mcpAnnotationMcpSyncClientCustomizer(List<SyncLoggingSpecification> loggingSpecs,
229-
List<SyncSamplingSpecification> samplingSpecs, List<SyncElicitationSpecification> elicitationSpecs,
230-
List<SyncProgressSpecification> progressSpecs,
231-
List<SyncToolListChangedSpecification> syncToolListChangedSpecifications,
232-
List<SyncResourceListChangedSpecification> syncResourceListChangedSpecifications,
233-
List<SyncPromptListChangedSpecification> syncPromptListChangedSpecifications) {
234-
return new McpSyncAnnotationCustomizer(samplingSpecs, loggingSpecs, elicitationSpecs, progressSpecs,
235-
syncToolListChangedSpecifications, syncResourceListChangedSpecifications,
236-
syncPromptListChangedSpecifications);
237-
}
238-
239227
// Async client configuration
240228

241229
@Bean
242230
@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
243231
public List<McpAsyncClient> mcpAsyncClients(McpAsyncClientConfigurer mcpAsyncClientConfigurer,
244232
McpClientCommonProperties commonProperties,
245-
ObjectProvider<List<NamedClientMcpTransport>> transportsProvider) {
233+
ObjectProvider<List<NamedClientMcpTransport>> transportsProvider,
234+
ClientMcpAsyncHandlersRegistry clientMcpAsyncHandlersRegistry) {
246235

247236
List<McpAsyncClient> mcpAsyncClients = new ArrayList<>();
248237

@@ -257,7 +246,22 @@ public List<McpAsyncClient> mcpAsyncClients(McpAsyncClientConfigurer mcpAsyncCli
257246

258247
McpClient.AsyncSpec spec = McpClient.async(namedTransport.transport())
259248
.clientInfo(clientInfo)
260-
.requestTimeout(commonProperties.getRequestTimeout());
249+
.requestTimeout(commonProperties.getRequestTimeout())
250+
.sampling(samplingRequest -> clientMcpAsyncHandlersRegistry.handleSampling(namedTransport.name(),
251+
samplingRequest))
252+
.elicitation(elicitationRequest -> clientMcpAsyncHandlersRegistry
253+
.handleElicitation(namedTransport.name(), elicitationRequest))
254+
.loggingConsumer(loggingMessageNotification -> clientMcpAsyncHandlersRegistry
255+
.handleLogging(namedTransport.name(), loggingMessageNotification))
256+
.progressConsumer(progressNotification -> clientMcpAsyncHandlersRegistry
257+
.handleProgress(namedTransport.name(), progressNotification))
258+
.toolsChangeConsumer(newTools -> clientMcpAsyncHandlersRegistry
259+
.handleToolListChanged(namedTransport.name(), newTools))
260+
.promptsChangeConsumer(newPrompts -> clientMcpAsyncHandlersRegistry
261+
.handlePromptListChanged(namedTransport.name(), newPrompts))
262+
.resourcesChangeConsumer(newResources -> clientMcpAsyncHandlersRegistry
263+
.handleResourceListChanged(namedTransport.name(), newResources))
264+
.capabilities(clientMcpAsyncHandlersRegistry.getCapabilities(namedTransport.name()));
261265

262266
spec = mcpAsyncClientConfigurer.configure(namedTransport.name(), spec);
263267

@@ -287,18 +291,6 @@ McpAsyncClientConfigurer mcpAsyncClientConfigurer(ObjectProvider<McpAsyncClientC
287291
return new McpAsyncClientConfigurer(customizerProvider.orderedStream().toList());
288292
}
289293

290-
@Bean
291-
@ConditionalOnProperty(prefix = McpClientCommonProperties.CONFIG_PREFIX, name = "type", havingValue = "ASYNC")
292-
public McpAsyncClientCustomizer mcpAnnotationMcpAsyncClientCustomizer(List<AsyncLoggingSpecification> loggingSpecs,
293-
List<AsyncSamplingSpecification> samplingSpecs, List<AsyncElicitationSpecification> elicitationSpecs,
294-
List<AsyncProgressSpecification> progressSpecs,
295-
List<AsyncToolListChangedSpecification> toolListChangedSpecs,
296-
List<AsyncResourceListChangedSpecification> resourceListChangedSpecs,
297-
List<AsyncPromptListChangedSpecification> promptListChangedSpecs) {
298-
return new McpAsyncAnnotationCustomizer(samplingSpecs, loggingSpecs, elicitationSpecs, progressSpecs,
299-
toolListChangedSpecs, resourceListChangedSpecs, promptListChangedSpecs);
300-
}
301-
302294
/**
303295
* Record class that implements {@link AutoCloseable} to ensure proper cleanup of MCP
304296
* clients.

0 commit comments

Comments
 (0)