Skip to content

Commit 8736660

Browse files
Spring AI 1.0.0-M6
1 parent 8e61635 commit 8736660

File tree

9 files changed

+76
-78
lines changed

9 files changed

+76
-78
lines changed

orchestration/pom.xml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131
</developers>
3232
<properties>
3333
<project.rootdir>${project.basedir}/../</project.rootdir>
34-
<coverage.complexity>80%</coverage.complexity>
35-
<coverage.line>93%</coverage.line>
36-
<coverage.instruction>93%</coverage.instruction>
34+
<coverage.complexity>79%</coverage.complexity>
35+
<coverage.line>92%</coverage.line>
36+
<coverage.instruction>92%</coverage.instruction>
3737
<coverage.branch>73%</coverage.branch>
38-
<coverage.method>92%</coverage.method>
38+
<coverage.method>90%</coverage.method>
3939
<coverage.class>100%</coverage.class>
4040
</properties>
4141

@@ -59,6 +59,11 @@
5959
<artifactId>spring-ai-core</artifactId>
6060
<optional>true</optional>
6161
</dependency>
62+
<dependency>
63+
<groupId>io.micrometer</groupId>
64+
<artifactId>micrometer-observation</artifactId>
65+
<optional>true</optional>
66+
</dependency>
6267
<dependency>
6368
<groupId>io.projectreactor</groupId>
6469
<artifactId>reactor-core</artifactId>

orchestration/src/main/java/com/sap/ai/sdk/orchestration/spring/OrchestrationChatModel.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import com.sap.ai.sdk.orchestration.UserMessage;
1414
import com.sap.ai.sdk.orchestration.model.ResponseMessageToolCall;
1515
import com.sap.ai.sdk.orchestration.model.ResponseMessageToolCallFunction;
16+
import io.micrometer.observation.ObservationRegistry;
1617
import java.util.List;
1718
import java.util.Map;
1819
import java.util.function.Function;
@@ -27,6 +28,8 @@
2728
import org.springframework.ai.model.tool.DefaultToolCallingManager;
2829
import org.springframework.ai.model.tool.ToolCallingChatOptions;
2930
import org.springframework.ai.model.tool.ToolExecutionResult;
31+
import org.springframework.ai.tool.execution.DefaultToolExecutionExceptionProcessor;
32+
import org.springframework.ai.tool.resolution.DelegatingToolCallbackResolver;
3033
import reactor.core.publisher.Flux;
3134

3235
/**
@@ -45,7 +48,10 @@ public class OrchestrationChatModel extends DefaultToolCallingManager implements
4548
* @since 1.2.0
4649
*/
4750
public OrchestrationChatModel() {
48-
super(null, null, null);
51+
super(
52+
ObservationRegistry.NOOP,
53+
new DelegatingToolCallbackResolver(List.of()),
54+
DefaultToolExecutionExceptionProcessor.builder().build());
4955
this.client = new OrchestrationClient();
5056
}
5157

@@ -55,7 +61,10 @@ public OrchestrationChatModel() {
5561
* @since 1.2.0
5662
*/
5763
public OrchestrationChatModel(@Nonnull final OrchestrationClient client) {
58-
super(null, null, null);
64+
super(
65+
ObservationRegistry.NOOP,
66+
new DelegatingToolCallbackResolver(List.of()),
67+
DefaultToolExecutionExceptionProcessor.builder().build());
5968
this.client = client;
6069
}
6170

@@ -64,29 +73,21 @@ public OrchestrationChatModel(@Nonnull final OrchestrationClient client) {
6473
public ChatResponse call(@Nonnull final Prompt prompt) {
6574
if (prompt.getOptions() instanceof OrchestrationChatOptions options) {
6675

67-
// if (options.getToolCallbacks() != null) {
68-
// runtimeToolCallbackConfigurations(
69-
// ToolCallingChatOptions.builder()
70-
// .toolCallbacks(options.getToolCallbacks())
71-
// .build());
72-
// }
73-
7476
val orchestrationPrompt = toOrchestrationPrompt(prompt);
7577
val response =
7678
new OrchestrationSpringChatResponse(
7779
client.chatCompletion(orchestrationPrompt, options.getConfig()));
7880

7981
if (ToolCallingChatOptions.isInternalToolExecutionEnabled(prompt.getOptions())
8082
&& response.hasToolCalls()) {
81-
var toolExecutionResult = this.executeToolCalls(prompt, response);
83+
val toolExecutionResult = this.executeToolCalls(prompt, response);
8284
if (toolExecutionResult.returnDirect()) {
8385
// Return tool execution result directly to the client.
8486
return ChatResponse.builder()
8587
.from(response)
8688
.generations(ToolExecutionResult.buildGenerations(toolExecutionResult))
8789
.build();
88-
}
89-
else {
90+
} else {
9091
// Send the tool execution result back to the model.
9192
return call(new Prompt(toolExecutionResult.conversationHistory(), prompt.getOptions()));
9293
}

orchestration/src/main/java/com/sap/ai/sdk/orchestration/spring/OrchestrationChatOptions.java

Lines changed: 37 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import org.springframework.ai.model.ModelOptionsUtils;
3030
import org.springframework.ai.model.function.FunctionCallback;
3131
import org.springframework.ai.model.tool.ToolCallingChatOptions;
32-
import org.springframework.ai.tool.ToolCallback;
3332

3433
/**
3534
* Configuration to be used for orchestration requests.
@@ -39,14 +38,15 @@
3938
@Beta
4039
@Data
4140
@Getter(AccessLevel.PUBLIC)
42-
public class OrchestrationChatOptions implements ToolCallingChatOptions
43-
{
41+
public class OrchestrationChatOptions implements ToolCallingChatOptions {
4442

4543
@Getter(AccessLevel.NONE)
4644
private static final ObjectMapper JACKSON = getOrchestrationObjectMapper();
4745

4846
@Nonnull private OrchestrationModuleConfig config;
4947

48+
private List<FunctionCallback> functionCallbacks;
49+
5050
/**
5151
* Returns the model to use for the chat.
5252
*
@@ -179,10 +179,26 @@ private LLMModuleConfig getLlmConfigNonNull() {
179179
"LLM config is not set. Please set it: new OrchestrationChatOptions(new OrchestrationModuleConfig().withLlmConfig(...))");
180180
}
181181

182-
private List<ToolCallback> toolCallbacks;
182+
@Nonnull
183+
@Override
184+
public List<FunctionCallback> getToolCallbacks() {
185+
return functionCallbacks;
186+
}
183187

184-
public void setToolCallbackss(@Nonnull final List<ToolCallback> toolCallbacks) {
185-
this.toolCallbacks = toolCallbacks;
188+
@Override
189+
public void setToolCallbacks(@Nonnull final List<FunctionCallback> toolCallbacks) {
190+
setFunctionCallbacks(toolCallbacks);
191+
}
192+
193+
@Nonnull
194+
@Override
195+
public List<FunctionCallback> getFunctionCallbacks() {
196+
return functionCallbacks;
197+
}
198+
199+
@Override
200+
public void setFunctionCallbacks(@Nonnull final List<FunctionCallback> toolCallbacks) {
201+
this.functionCallbacks = toolCallbacks;
186202
final Template template =
187203
Objects.requireNonNullElse(
188204
(Template) config.getTemplateConfig(), Template.create().template());
@@ -194,74 +210,42 @@ public void setToolCallbackss(@Nonnull final List<ToolCallback> toolCallbacks) {
194210
.type(TypeEnum.FUNCTION)
195211
.function(
196212
FunctionObject.create()
197-
.name(functionCallback.getToolDefinition().name())
198-
.description(functionCallback.getToolDefinition().description())
213+
.name(functionCallback.getName())
214+
.description(functionCallback.getDescription())
199215
.parameters(
200216
ModelOptionsUtils.jsonToMap(
201-
functionCallback.getToolDefinition().inputSchema()))))
217+
functionCallback.getInputTypeSchema()))))
202218
.toList();
203219
config = config.withTemplateConfig(template.tools(tools));
204220
}
205221

206-
// -------------------DEPRECATED-------------------
207-
@Override
208-
public List<FunctionCallback> getToolCallbacks()
209-
{
210-
return List.of();
211-
}
212-
213-
@Override
214-
public void setToolCallbacks( List<FunctionCallback> toolCallbacks )
215-
{
216-
217-
}
218-
219-
@Override
220-
public List<FunctionCallback> getFunctionCallbacks()
221-
{
222-
return List.of();
223-
}
224-
225-
@Override
226-
public void setFunctionCallbacks(@Nonnull final List<FunctionCallback> functionCallbacks) {
227-
228-
}
229-
230-
// -------------------TODO-------------------
231222
@Nonnull
232223
@Override
233-
public Set<String> getToolNames()
234-
{
224+
public Set<String> getToolNames() {
235225
return Set.of();
236226
}
237227

238228
@Override
239-
public void setToolNames( @Nonnull final Set<String> toolNames )
240-
{
241-
242-
}
229+
public void setToolNames(@Nonnull final Set<String> toolNames) {}
243230

231+
@Nullable
244232
@Override
245-
public Boolean isInternalToolExecutionEnabled()
246-
{
233+
public Boolean isInternalToolExecutionEnabled() {
247234
return null;
248235
}
249236

250237
@Override
251-
public void setInternalToolExecutionEnabled( Boolean internalToolExecutionEnabled )
252-
{
253-
254-
}
238+
public void setInternalToolExecutionEnabled(
239+
@Nullable final Boolean internalToolExecutionEnabled) {}
255240

241+
@Nonnull
256242
@Override
257-
public Set<String> getFunctions()
258-
{
243+
public Set<String> getFunctions() {
259244
return Set.of();
260245
}
261246

262247
@Override
263-
public void setFunctions( Set<String> functions )
264-
{
248+
public void setFunctions(@Nonnull final Set<String> functions) {
265249
// val template =
266250
// Objects.requireNonNullElse(
267251
// (Template) config.getTemplateConfig(), Template.create().template());
@@ -277,15 +261,14 @@ public void setFunctions( Set<String> functions )
277261
throw new UnsupportedOperationException("Not implemented yet");
278262
}
279263

264+
@Nonnull
280265
@Override
281-
public Map<String, Object> getToolContext()
282-
{
266+
public Map<String, Object> getToolContext() {
283267
return Map.of();
284268
}
285269

286270
@Override
287-
public void setToolContext( Map<String, Object> tooContext )
288-
{
271+
public void setToolContext(@Nonnull final Map<String, Object> tooContext) {
289272
throw new UnsupportedOperationException("Not implemented yet");
290273
}
291274
}

orchestration/src/test/java/com/sap/ai/sdk/orchestration/spring/OrchestrationChatModelTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
import org.mockito.Mockito;
4242
import org.springframework.ai.chat.model.ChatResponse;
4343
import org.springframework.ai.chat.prompt.Prompt;
44-
import org.springframework.ai.tool.ToolCallback;
44+
import org.springframework.ai.tool.function.FunctionToolCallback;
4545
import reactor.core.publisher.Flux;
4646

4747
@WireMockTest
@@ -166,8 +166,7 @@ void testToolCalls() throws IOException {
166166

167167
defaultOptions.setToolCallbacks(
168168
List.of(
169-
ToolCallback.builder()
170-
.function(
169+
FunctionToolCallback.builder(
171170
"CurrentWeather", new MockWeatherService()) // (1) function name and instance
172171
.description("Get the weather in location") // (2) function description
173172
.inputType(MockWeatherService.Request.class) // (3) function input type

orchestration/src/test/java/com/sap/ai/sdk/orchestration/spring/OrchestrationChatResponseTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void testToChatResponseMetadata() {
4848
var usage = metadata.getUsage();
4949

5050
assertThat(usage.getPromptTokens()).isEqualTo(10L);
51-
assertThat(usage.getGenerationTokens()).isEqualTo(20L);
51+
assertThat(usage.getCompletionTokens()).isEqualTo(20L);
5252
assertThat(usage.getTotalTokens()).isEqualTo(30L);
5353
}
5454
}

orchestration/src/test/resources/toolCallsRequest.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"name": "CurrentWeather",
2323
"parameters": {
2424
"$schema": "https://json-schema.org/draft/2020-12/schema",
25+
"additionalProperties": false,
2526
"type": "object",
2627
"properties": {
2728
"location": {
@@ -34,7 +35,11 @@
3435
"F"
3536
]
3637
}
37-
}
38+
},
39+
"required": [
40+
"location",
41+
"unit"
42+
]
3843
},
3944
"strict": false
4045
}

orchestration/src/test/resources/toolCallsRequest2.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"name": "CurrentWeather",
5555
"parameters": {
5656
"$schema": "https://json-schema.org/draft/2020-12/schema",
57+
"additionalProperties": false,
5758
"type": "object",
5859
"properties": {
5960
"location": {
@@ -66,7 +67,11 @@
6667
"F"
6768
]
6869
}
69-
}
70+
},
71+
"required": [
72+
"location",
73+
"unit"
74+
]
7075
},
7176
"strict": false
7277
}

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
<system-stubs.version>2.1.3</system-stubs.version>
6565
<surefire.version>3.5.2</surefire.version>
6666
<springframework.version>6.2.1</springframework.version>
67-
<spring-ai.version>1.0.0-SNAPSHOT</spring-ai.version>
67+
<spring-ai.version>1.0.0-M6</spring-ai.version>
6868
<reactor-core.version>3.6.12</reactor-core.version>
6969
<dotenv-java.version>3.1.0</dotenv-java.version>
7070
<mockito.version>5.15.2</mockito.version>

sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/SpringAiOrchestrationService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public ChatResponse masking() {
100100
@Nonnull
101101
public ChatResponse functionCalling() {
102102
final OrchestrationChatOptions options = new OrchestrationChatOptions(config);
103-
options.setToolCallbackss(
103+
options.setToolCallbacks(
104104
List.of(
105105
FunctionToolCallback.builder("CurrentWeather", new MockWeatherService())
106106
.description("Get the weather in location") // (2) function description

0 commit comments

Comments
 (0)