Skip to content

Commit 33c25ee

Browse files
committed
refactor: introduce FunctionCallbackResolver interface
- Introduces a new FunctionCallbackResolver interface to define the strategy for resolving FunctionCallback instances from the application context. - Renames FunctionCallbackContext to DefaultFunctionCallbackResolver to better reflect its implementation role. Updates all related components to use the new interface. - Update the affected AI model implementations - Replaces FunctionCallbackContext parameter with FunctionCallbackResolver in all model constructors - Updates builder patterns to use functionCallbackResolver() method instead of withFunctionCallbackContext() - Deprecates old withFunctionCallbackContext() methods in builders to guide migration - Updates integration tests to use DefaultFunctionCallbackResolver - Improves documentation to clarify the resolver's role in function callbacks - Moves SchemaType enum from FunctionCallbackContext to FunctionCallback (Braking change)git add . Resolves #758
1 parent c057148 commit 33c25ee

File tree

43 files changed

+289
-200
lines changed

Some content is hidden

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

43 files changed

+289
-200
lines changed

models/spring-ai-anthropic/src/main/java/org/springframework/ai/anthropic/AnthropicChatModel.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
import org.springframework.ai.chat.prompt.Prompt;
6161
import org.springframework.ai.model.ModelOptionsUtils;
6262
import org.springframework.ai.model.function.FunctionCallback;
63-
import org.springframework.ai.model.function.FunctionCallbackContext;
63+
import org.springframework.ai.model.function.FunctionCallbackResolver;
6464
import org.springframework.ai.model.function.FunctionCallingOptions;
6565
import org.springframework.ai.retry.RetryUtils;
6666
import org.springframework.http.ResponseEntity;
@@ -154,29 +154,29 @@ public AnthropicChatModel(AnthropicApi anthropicApi, AnthropicChatOptions defaul
154154
* @param anthropicApi the lower-level API for the Anthropic service.
155155
* @param defaultOptions the default options used for the chat completion requests.
156156
* @param retryTemplate the retry template used to retry the Anthropic API calls.
157-
* @param functionCallbackContext the function callback context used to store the
158-
* state of the function calls.
157+
* @param functionCallbackResolver the function callback resolver used to resolve the
158+
* function by bean name.s
159159
*/
160160
public AnthropicChatModel(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
161-
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext) {
161+
RetryTemplate retryTemplate, FunctionCallbackResolver functionCallbackResolver) {
162162

163-
this(anthropicApi, defaultOptions, retryTemplate, functionCallbackContext, List.of());
163+
this(anthropicApi, defaultOptions, retryTemplate, functionCallbackResolver, List.of());
164164
}
165165

166166
/**
167167
* Construct a new {@link AnthropicChatModel} instance.
168168
* @param anthropicApi the lower-level API for the Anthropic service.
169169
* @param defaultOptions the default options used for the chat completion requests.
170170
* @param retryTemplate the retry template used to retry the Anthropic API calls.
171-
* @param functionCallbackContext the function callback context used to store the
172-
* state of the function calls.
171+
* @param functionCallbackResolver the function callback resolver used to resolve the
172+
* function by bean name.
173173
* @param toolFunctionCallbacks the tool function callbacks used to handle the tool
174174
* calls.
175175
*/
176176
public AnthropicChatModel(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
177-
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext,
177+
RetryTemplate retryTemplate, FunctionCallbackResolver functionCallbackResolver,
178178
List<FunctionCallback> toolFunctionCallbacks) {
179-
this(anthropicApi, defaultOptions, retryTemplate, functionCallbackContext, toolFunctionCallbacks,
179+
this(anthropicApi, defaultOptions, retryTemplate, functionCallbackResolver, toolFunctionCallbacks,
180180
ObservationRegistry.NOOP);
181181
}
182182

@@ -185,16 +185,16 @@ public AnthropicChatModel(AnthropicApi anthropicApi, AnthropicChatOptions defaul
185185
* @param anthropicApi the lower-level API for the Anthropic service.
186186
* @param defaultOptions the default options used for the chat completion requests.
187187
* @param retryTemplate the retry template used to retry the Anthropic API calls.
188-
* @param functionCallbackContext the function callback context used to store the
189-
* state of the function calls.
188+
* @param functionCallbackResolver the function callback resolver used to resolve the
189+
* function by bean name.
190190
* @param toolFunctionCallbacks the tool function callbacks used to handle the tool
191191
* calls.
192192
*/
193193
public AnthropicChatModel(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
194-
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext,
194+
RetryTemplate retryTemplate, FunctionCallbackResolver functionCallbackResolver,
195195
List<FunctionCallback> toolFunctionCallbacks, ObservationRegistry observationRegistry) {
196196

197-
super(functionCallbackContext, defaultOptions, toolFunctionCallbacks);
197+
super(functionCallbackResolver, defaultOptions, toolFunctionCallbacks);
198198

199199
Assert.notNull(anthropicApi, "AnthropicApi must not be null");
200200
Assert.notNull(defaultOptions, "DefaultOptions must not be null");

models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic/AnthropicChatModelObservationIT.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
import org.springframework.ai.chat.observation.ChatModelObservationDocumentation.LowCardinalityKeyNames;
3434
import org.springframework.ai.chat.observation.DefaultChatModelObservationConvention;
3535
import org.springframework.ai.chat.prompt.Prompt;
36-
import org.springframework.ai.model.function.FunctionCallbackContext;
36+
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
3737
import org.springframework.ai.observation.conventions.AiOperationType;
3838
import org.springframework.ai.observation.conventions.AiProvider;
3939
import org.springframework.beans.factory.annotation.Autowired;
@@ -170,7 +170,8 @@ public AnthropicApi anthropicApi() {
170170
public AnthropicChatModel anthropicChatModel(AnthropicApi anthropicApi,
171171
TestObservationRegistry observationRegistry) {
172172
return new AnthropicChatModel(anthropicApi, AnthropicChatOptions.builder().build(),
173-
RetryTemplate.defaultInstance(), new FunctionCallbackContext(), List.of(), observationRegistry);
173+
RetryTemplate.defaultInstance(), new DefaultFunctionCallbackResolver(), List.of(),
174+
observationRegistry);
174175
}
175176

176177
}

models/spring-ai-azure-openai/src/main/java/org/springframework/ai/azure/openai/AzureOpenAiChatModel.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
import org.springframework.ai.model.Media;
8484
import org.springframework.ai.model.ModelOptionsUtils;
8585
import org.springframework.ai.model.function.FunctionCallback;
86-
import org.springframework.ai.model.function.FunctionCallbackContext;
86+
import org.springframework.ai.model.function.FunctionCallbackResolver;
8787
import org.springframework.ai.model.function.FunctionCallingOptions;
8888
import org.springframework.ai.observation.conventions.AiProvider;
8989
import org.springframework.util.Assert;
@@ -154,19 +154,19 @@ public AzureOpenAiChatModel(OpenAIClientBuilder openAIClientBuilder, AzureOpenAi
154154
}
155155

156156
public AzureOpenAiChatModel(OpenAIClientBuilder openAIClientBuilder, AzureOpenAiChatOptions options,
157-
FunctionCallbackContext functionCallbackContext) {
158-
this(openAIClientBuilder, options, functionCallbackContext, List.of());
157+
FunctionCallbackResolver functionCallbackResolver) {
158+
this(openAIClientBuilder, options, functionCallbackResolver, List.of());
159159
}
160160

161161
public AzureOpenAiChatModel(OpenAIClientBuilder openAIClientBuilder, AzureOpenAiChatOptions options,
162-
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks) {
163-
this(openAIClientBuilder, options, functionCallbackContext, toolFunctionCallbacks, ObservationRegistry.NOOP);
162+
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks) {
163+
this(openAIClientBuilder, options, functionCallbackResolver, toolFunctionCallbacks, ObservationRegistry.NOOP);
164164
}
165165

166166
public AzureOpenAiChatModel(OpenAIClientBuilder openAIClientBuilder, AzureOpenAiChatOptions options,
167-
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
167+
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
168168
ObservationRegistry observationRegistry) {
169-
super(functionCallbackContext, options, toolFunctionCallbacks);
169+
super(functionCallbackResolver, options, toolFunctionCallbacks);
170170
Assert.notNull(openAIClientBuilder, "com.azure.ai.openai.OpenAIClient must not be null");
171171
Assert.notNull(options, "AzureOpenAiChatOptions must not be null");
172172
this.openAIClient = openAIClientBuilder.buildClient();

models/spring-ai-azure-openai/src/test/java/org/springframework/ai/azure/openai/AzureOpenAiChatModelTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import org.mockito.junit.jupiter.MockitoExtension;
2626

2727
import org.springframework.ai.model.function.FunctionCallback;
28-
import org.springframework.ai.model.function.FunctionCallbackContext;
28+
import org.springframework.ai.model.function.FunctionCallbackResolver;
2929

3030
/**
3131
* @author Jihoon Kim
@@ -37,7 +37,7 @@ public class AzureOpenAiChatModelTests {
3737
OpenAIClientBuilder mockClient;
3838

3939
@Mock
40-
FunctionCallbackContext functionCallbackContext;
40+
FunctionCallbackResolver functionCallbackResolver;
4141

4242
@Test
4343
public void createAzureOpenAiChatModelTest() {
@@ -51,7 +51,7 @@ public void createAzureOpenAiChatModelTest() {
5151
List<FunctionCallback> functionCallbacks = List.of(new TestFunctionCallback(callbackFromConstructorParam));
5252

5353
AzureOpenAiChatModel openAiChatModel = new AzureOpenAiChatModel(this.mockClient, chatOptions,
54-
this.functionCallbackContext, functionCallbacks);
54+
this.functionCallbackResolver, functionCallbacks);
5555

5656
assert 2 == openAiChatModel.getFunctionCallbackRegister().size();
5757

models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModel.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
import org.springframework.ai.chat.prompt.Prompt;
8989
import org.springframework.ai.model.ModelOptionsUtils;
9090
import org.springframework.ai.model.function.FunctionCallback;
91-
import org.springframework.ai.model.function.FunctionCallbackContext;
91+
import org.springframework.ai.model.function.FunctionCallbackResolver;
9292
import org.springframework.ai.model.function.FunctionCallingOptions;
9393
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder;
9494
import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
@@ -146,10 +146,10 @@ public class BedrockProxyChatModel extends AbstractToolCallSupport implements Ch
146146

147147
public BedrockProxyChatModel(BedrockRuntimeClient bedrockRuntimeClient,
148148
BedrockRuntimeAsyncClient bedrockRuntimeAsyncClient, FunctionCallingOptions defaultOptions,
149-
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
149+
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
150150
ObservationRegistry observationRegistry) {
151151

152-
super(functionCallbackContext, defaultOptions, toolFunctionCallbacks);
152+
super(functionCallbackResolver, defaultOptions, toolFunctionCallbacks);
153153

154154
Assert.notNull(bedrockRuntimeClient, "bedrockRuntimeClient must not be null");
155155
Assert.notNull(bedrockRuntimeAsyncClient, "bedrockRuntimeAsyncClient must not be null");
@@ -609,7 +609,7 @@ public static final class Builder {
609609

610610
private FunctionCallingOptions defaultOptions = new FunctionCallingOptionsBuilder().build();
611611

612-
private FunctionCallbackContext functionCallbackContext;
612+
private FunctionCallbackResolver functionCallbackResolver;
613613

614614
private List<FunctionCallback> toolFunctionCallbacks;
615615

@@ -648,8 +648,18 @@ public Builder withDefaultOptions(FunctionCallingOptions defaultOptions) {
648648
return this;
649649
}
650650

651-
public Builder withFunctionCallbackContext(FunctionCallbackContext functionCallbackContext) {
652-
this.functionCallbackContext = functionCallbackContext;
651+
/**
652+
* @deprecated Use {@link #functionCallbackResolver(FunctionCallbackResolver)}
653+
* instead.
654+
*/
655+
@Deprecated
656+
public Builder withFunctionCallbackContext(FunctionCallbackResolver functionCallbackResolver) {
657+
this.functionCallbackResolver = functionCallbackResolver;
658+
return this;
659+
}
660+
661+
public Builder functionCallbackResolver(FunctionCallbackResolver functionCallbackResolver) {
662+
this.functionCallbackResolver = functionCallbackResolver;
653663
return this;
654664
}
655665

@@ -708,7 +718,7 @@ public BedrockProxyChatModel build() {
708718
}
709719

710720
var bedrockProxyChatModel = new BedrockProxyChatModel(this.bedrockRuntimeClient,
711-
this.bedrockRuntimeAsyncClient, this.defaultOptions, this.functionCallbackContext,
721+
this.bedrockRuntimeAsyncClient, this.defaultOptions, this.functionCallbackResolver,
712722
this.toolFunctionCallbacks, this.observationRegistry);
713723

714724
if (this.customObservationConvention != null) {

models/spring-ai-minimax/src/main/java/org/springframework/ai/minimax/MiniMaxChatModel.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
import org.springframework.ai.minimax.metadata.MiniMaxUsage;
6565
import org.springframework.ai.model.ModelOptionsUtils;
6666
import org.springframework.ai.model.function.FunctionCallback;
67-
import org.springframework.ai.model.function.FunctionCallbackContext;
67+
import org.springframework.ai.model.function.FunctionCallbackResolver;
6868
import org.springframework.ai.model.function.FunctionCallingOptions;
6969
import org.springframework.ai.retry.RetryUtils;
7070
import org.springframework.http.ResponseEntity;
@@ -139,28 +139,30 @@ public MiniMaxChatModel(MiniMaxApi miniMaxApi, MiniMaxChatOptions options) {
139139
* @param miniMaxApi The MiniMaxApi instance to be used for interacting with the
140140
* MiniMax Chat API.
141141
* @param options The MiniMaxChatOptions to configure the chat model.
142-
* @param functionCallbackContext The function callback context.
142+
* @param functionCallbackResolver The function callback resolver to resolve the
143+
* function callback from the application context.
143144
* @param retryTemplate The retry template.
144145
*/
145146
public MiniMaxChatModel(MiniMaxApi miniMaxApi, MiniMaxChatOptions options,
146-
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate) {
147-
this(miniMaxApi, options, functionCallbackContext, List.of(), retryTemplate, ObservationRegistry.NOOP);
147+
FunctionCallbackResolver functionCallbackResolver, RetryTemplate retryTemplate) {
148+
this(miniMaxApi, options, functionCallbackResolver, List.of(), retryTemplate, ObservationRegistry.NOOP);
148149
}
149150

150151
/**
151152
* Initializes a new instance of the MiniMaxChatModel.
152153
* @param miniMaxApi The MiniMaxApi instance to be used for interacting with the
153154
* MiniMax Chat API.
154155
* @param options The MiniMaxChatOptions to configure the chat model.
155-
* @param functionCallbackContext The function callback context.
156+
* @param functionCallbackResolver The function callback resolver to resolve the
157+
* function callback from the application context.
156158
* @param toolFunctionCallbacks The tool function callbacks.
157159
* @param retryTemplate The retry template.
158160
* @param observationRegistry The ObservationRegistry used for instrumentation.
159161
*/
160162
public MiniMaxChatModel(MiniMaxApi miniMaxApi, MiniMaxChatOptions options,
161-
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
163+
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
162164
RetryTemplate retryTemplate, ObservationRegistry observationRegistry) {
163-
super(functionCallbackContext, options, toolFunctionCallbacks);
165+
super(functionCallbackResolver, options, toolFunctionCallbacks);
164166
Assert.notNull(miniMaxApi, "MiniMaxApi must not be null");
165167
Assert.notNull(options, "Options must not be null");
166168
Assert.notNull(retryTemplate, "RetryTemplate must not be null");

models/spring-ai-minimax/src/test/java/org/springframework/ai/minimax/chat/MiniMaxChatModelObservationIT.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
import org.springframework.ai.minimax.MiniMaxChatModel;
3434
import org.springframework.ai.minimax.MiniMaxChatOptions;
3535
import org.springframework.ai.minimax.api.MiniMaxApi;
36-
import org.springframework.ai.model.function.FunctionCallbackContext;
36+
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
3737
import org.springframework.ai.observation.conventions.AiOperationType;
3838
import org.springframework.ai.observation.conventions.AiProvider;
3939
import org.springframework.beans.factory.annotation.Autowired;
@@ -170,8 +170,9 @@ public MiniMaxApi minimaxApi() {
170170

171171
@Bean
172172
public MiniMaxChatModel minimaxChatModel(MiniMaxApi minimaxApi, TestObservationRegistry observationRegistry) {
173-
return new MiniMaxChatModel(minimaxApi, MiniMaxChatOptions.builder().build(), new FunctionCallbackContext(),
174-
List.of(), RetryTemplate.defaultInstance(), observationRegistry);
173+
return new MiniMaxChatModel(minimaxApi, MiniMaxChatOptions.builder().build(),
174+
new DefaultFunctionCallbackResolver(), List.of(), RetryTemplate.defaultInstance(),
175+
observationRegistry);
175176
}
176177

177178
}

models/spring-ai-mistral-ai/src/main/java/org/springframework/ai/mistralai/MistralAiChatModel.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
import org.springframework.ai.mistralai.metadata.MistralAiUsage;
6060
import org.springframework.ai.model.ModelOptionsUtils;
6161
import org.springframework.ai.model.function.FunctionCallback;
62-
import org.springframework.ai.model.function.FunctionCallbackContext;
62+
import org.springframework.ai.model.function.FunctionCallbackResolver;
6363
import org.springframework.ai.model.function.FunctionCallingOptions;
6464
import org.springframework.ai.retry.RetryUtils;
6565
import org.springframework.http.ResponseEntity;
@@ -120,21 +120,21 @@ public MistralAiChatModel(MistralAiApi mistralAiApi, MistralAiChatOptions option
120120
}
121121

122122
public MistralAiChatModel(MistralAiApi mistralAiApi, MistralAiChatOptions options,
123-
FunctionCallbackContext functionCallbackContext, RetryTemplate retryTemplate) {
124-
this(mistralAiApi, options, functionCallbackContext, List.of(), retryTemplate);
123+
FunctionCallbackResolver functionCallbackResolver, RetryTemplate retryTemplate) {
124+
this(mistralAiApi, options, functionCallbackResolver, List.of(), retryTemplate);
125125
}
126126

127127
public MistralAiChatModel(MistralAiApi mistralAiApi, MistralAiChatOptions options,
128-
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
128+
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
129129
RetryTemplate retryTemplate) {
130-
this(mistralAiApi, options, functionCallbackContext, toolFunctionCallbacks, retryTemplate,
130+
this(mistralAiApi, options, functionCallbackResolver, toolFunctionCallbacks, retryTemplate,
131131
ObservationRegistry.NOOP);
132132
}
133133

134134
public MistralAiChatModel(MistralAiApi mistralAiApi, MistralAiChatOptions options,
135-
FunctionCallbackContext functionCallbackContext, List<FunctionCallback> toolFunctionCallbacks,
135+
FunctionCallbackResolver functionCallbackResolver, List<FunctionCallback> toolFunctionCallbacks,
136136
RetryTemplate retryTemplate, ObservationRegistry observationRegistry) {
137-
super(functionCallbackContext, options, toolFunctionCallbacks);
137+
super(functionCallbackResolver, options, toolFunctionCallbacks);
138138
Assert.notNull(mistralAiApi, "mistralAiApi must not be null");
139139
Assert.notNull(options, "options must not be null");
140140
Assert.notNull(retryTemplate, "retryTemplate must not be null");

models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelObservationIT.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
import org.springframework.ai.chat.observation.DefaultChatModelObservationConvention;
3333
import org.springframework.ai.chat.prompt.Prompt;
3434
import org.springframework.ai.mistralai.api.MistralAiApi;
35-
import org.springframework.ai.model.function.FunctionCallbackContext;
35+
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
3636
import org.springframework.ai.observation.conventions.AiOperationType;
3737
import org.springframework.ai.observation.conventions.AiProvider;
3838
import org.springframework.beans.factory.annotation.Autowired;
@@ -181,7 +181,8 @@ public MistralAiApi mistralAiApi() {
181181
public MistralAiChatModel openAiChatModel(MistralAiApi mistralAiApi,
182182
TestObservationRegistry observationRegistry) {
183183
return new MistralAiChatModel(mistralAiApi, MistralAiChatOptions.builder().build(),
184-
new FunctionCallbackContext(), List.of(), RetryTemplate.defaultInstance(), observationRegistry);
184+
new DefaultFunctionCallbackResolver(), List.of(), RetryTemplate.defaultInstance(),
185+
observationRegistry);
185186
}
186187

187188
}

0 commit comments

Comments
 (0)