Skip to content

Commit 479a095

Browse files
tzolovilayaperumalg
authored andcommitted
refactor: introduce FunctionCallbackResolver interface
- Introduces a new FunctionCallbackResolver interface to define the strategy for resolving FunctionCallback instances. - 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 Resolves #758
1 parent 308d8d4 commit 479a095

File tree

43 files changed

+291
-206
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

+291
-206
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
@@ -62,7 +62,7 @@
6262
import org.springframework.ai.model.Media;
6363
import org.springframework.ai.model.ModelOptionsUtils;
6464
import org.springframework.ai.model.function.FunctionCallback;
65-
import org.springframework.ai.model.function.FunctionCallbackContext;
65+
import org.springframework.ai.model.function.FunctionCallbackResolver;
6666
import org.springframework.ai.model.function.FunctionCallingOptions;
6767
import org.springframework.ai.retry.RetryUtils;
6868
import org.springframework.http.ResponseEntity;
@@ -156,29 +156,29 @@ public AnthropicChatModel(AnthropicApi anthropicApi, AnthropicChatOptions defaul
156156
* @param anthropicApi the lower-level API for the Anthropic service.
157157
* @param defaultOptions the default options used for the chat completion requests.
158158
* @param retryTemplate the retry template used to retry the Anthropic API calls.
159-
* @param functionCallbackContext the function callback context used to store the
160-
* state of the function calls.
159+
* @param functionCallbackResolver the function callback resolver used to resolve the
160+
* function by its name.
161161
*/
162162
public AnthropicChatModel(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
163-
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext) {
163+
RetryTemplate retryTemplate, FunctionCallbackResolver functionCallbackResolver) {
164164

165-
this(anthropicApi, defaultOptions, retryTemplate, functionCallbackContext, List.of());
165+
this(anthropicApi, defaultOptions, retryTemplate, functionCallbackResolver, List.of());
166166
}
167167

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

@@ -187,16 +187,16 @@ public AnthropicChatModel(AnthropicApi anthropicApi, AnthropicChatOptions defaul
187187
* @param anthropicApi the lower-level API for the Anthropic service.
188188
* @param defaultOptions the default options used for the chat completion requests.
189189
* @param retryTemplate the retry template used to retry the Anthropic API calls.
190-
* @param functionCallbackContext the function callback context used to store the
191-
* state of the function calls.
190+
* @param functionCallbackResolver the function callback resolver used to resolve the
191+
* function by its name.
192192
* @param toolFunctionCallbacks the tool function callbacks used to handle the tool
193193
* calls.
194194
*/
195195
public AnthropicChatModel(AnthropicApi anthropicApi, AnthropicChatOptions defaultOptions,
196-
RetryTemplate retryTemplate, FunctionCallbackContext functionCallbackContext,
196+
RetryTemplate retryTemplate, FunctionCallbackResolver functionCallbackResolver,
197197
List<FunctionCallback> toolFunctionCallbacks, ObservationRegistry observationRegistry) {
198198

199-
super(functionCallbackContext, defaultOptions, toolFunctionCallbacks);
199+
super(functionCallbackResolver, defaultOptions, toolFunctionCallbacks);
200200

201201
Assert.notNull(anthropicApi, "AnthropicApi must not be null");
202202
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");
@@ -608,7 +608,7 @@ public static final class Builder {
608608

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

611-
private FunctionCallbackContext functionCallbackContext;
611+
private FunctionCallbackResolver functionCallbackResolver;
612612

613613
private List<FunctionCallback> toolFunctionCallbacks;
614614

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

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

@@ -707,7 +717,7 @@ public BedrockProxyChatModel build() {
707717
}
708718

709719
var bedrockProxyChatModel = new BedrockProxyChatModel(this.bedrockRuntimeClient,
710-
this.bedrockRuntimeAsyncClient, this.defaultOptions, this.functionCallbackContext,
720+
this.bedrockRuntimeAsyncClient, this.defaultOptions, this.functionCallbackResolver,
711721
this.toolFunctionCallbacks, this.observationRegistry);
712722

713723
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 by its name.
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 by its name.
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)