Skip to content

Commit b9150cb

Browse files
rpanackalbot-sdk-jsCharlesDuboisSAPnewtork
authored
fix: [Orchestration] V2 spec update (#482)
* Update orchestration based on fix/streaming-response-type * WiP * Latest spec with error classes * regenerate * regenerate * DPI * feat: Add embeddings endpoint and refactor orchestration client (#464) Co-authored-by: Roshin Rajan Panackal <[email protected]> * fix: [Orchestration] Spec update - Filtering, Remove "Synchronous" suffix and Embedding property renaming (#469) * Introduce filtering schema changes and update generated class names - synchronous suffix removed - `createConfig` removed from `ContentFilter` - release notes updated for filtering changes * Introduce filtering schema changes and update generated class names - synchronous suffix removed - `createConfig` removed from `ContentFilter` - release notes updated for filtering changes * Release notes and jacoco coverage work around * Lower min required jacoco coverage complexity and branch rating. - Release note paraphrasing * Update e2e for input filters --------- Co-authored-by: Roshin Rajan Panackal <[email protected]> * Make embedding client endpoint non-visible and update javadoc (minor) * Integrate v2 spec changes - `ConfigToRequestTransformer` (not fixed) * merge main * `ConfigToRequestTransformer` ready and adapt some tests (minimal) * Formatting * Partial migration of payload to v2 * All json updated * refactor (minor) and renaming * jacoco min threshold lowered * Formatting * Fix e2e test issue * Fix merge error * Formatting * update release notes * partial merge fix * Fix tests and add new mixin for filtering response * Include ErrorResponseStreaming * Update unit testing stream completion * better javadoc and getVersion fix -> getModelVersion * Minor syntax improvement * change from abstract class to interface * Fix message * Add comment --------- Co-authored-by: SAP Cloud SDK Bot <[email protected]> Co-authored-by: I538344 <[email protected]> Co-authored-by: Roshin Rajan Panackal <[email protected]> Co-authored-by: Alexander Dümont <[email protected]>
1 parent 8cc7024 commit b9150cb

File tree

88 files changed

+3491
-2329
lines changed

Some content is hidden

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

88 files changed

+3491
-2329
lines changed

core/src/main/java/com/sap/ai/sdk/core/common/ClientResponseHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class ClientResponseHandler<T, R extends ClientError, E extends ClientExc
3636
@Nonnull final Class<T> successType;
3737

3838
/** The HTTP error response type */
39-
@Nonnull final Class<R> errorType;
39+
@Nonnull final Class<? extends R> errorType;
4040

4141
/** The factory to create exceptions for Http 4xx/5xx responses. */
4242
@Nonnull final ClientExceptionFactory<E, R> exceptionFactory;

core/src/main/java/com/sap/ai/sdk/core/common/ClientStreamingHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public ClientStreamingHandler<D, R, E> objectMapper(@Nonnull final ObjectMapper
4343
*/
4444
public ClientStreamingHandler(
4545
@Nonnull final Class<D> deltaType,
46-
@Nonnull final Class<R> errorType,
46+
@Nonnull final Class<? extends R> errorType,
4747
@Nonnull final ClientExceptionFactory<E, R> exceptionFactory) {
4848
super(deltaType, errorType, exceptionFactory);
4949
}

docs/release_notes.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
- The `OrchestrationChatOptions` have been, replacing all references to `FunctionCallback` with `ToolCallback`.
1313
- Please follow the [official Spring AI upgrade guide](https://docs.spring.io/spring-ai/reference/upgrade-notes.html#upgrading-to-1-0-0-RC1) for further details.
1414
- The `@Beta` annotations on all classes related to Spring AI have been removed.
15-
15+
- [Orchestration] The `completion` api have been moved to the latest version `/v2/completions`
16+
- `LLMModuleConfig` is replaced by `LLMModelDetails` in `withLLmConfig` method of `OrchestrationModuleConfig` class.
17+
- `PromptTemplatingModuleConfigPrompt` replaces `TemplatingModuleConfig` in the `withTemplateConfig` method of `OrchestrationModuleConfig` class.
18+
- The generated model classes will reflect payload updates including restructuring of the module configurations and renaming of several fields.
1619

1720
### ✨ New Functionality
1821

orchestration/pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@
3636
</scm>
3737
<properties>
3838
<project.rootdir>${project.basedir}/../</project.rootdir>
39-
<coverage.complexity>82%</coverage.complexity>
39+
<coverage.complexity>80%</coverage.complexity>
4040
<coverage.line>94%</coverage.line>
41-
<coverage.instruction>95%</coverage.instruction>
42-
<coverage.branch>77%</coverage.branch>
41+
<coverage.instruction>94%</coverage.instruction>
42+
<coverage.branch>75%</coverage.branch>
4343
<coverage.method>93%</coverage.method>
4444
<coverage.class>100%</coverage.class>
4545
</properties>

orchestration/src/main/java/com/sap/ai/sdk/orchestration/ConfigToRequestTransformer.java

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
import com.sap.ai.sdk.orchestration.model.CompletionPostRequest;
55
import com.sap.ai.sdk.orchestration.model.ModuleConfigs;
66
import com.sap.ai.sdk.orchestration.model.OrchestrationConfig;
7+
import com.sap.ai.sdk.orchestration.model.PromptTemplatingModuleConfig;
8+
import com.sap.ai.sdk.orchestration.model.PromptTemplatingModuleConfigPrompt;
79
import com.sap.ai.sdk.orchestration.model.Template;
810
import com.sap.ai.sdk.orchestration.model.TemplateRef;
9-
import com.sap.ai.sdk.orchestration.model.TemplatingModuleConfig;
11+
import com.sap.ai.sdk.orchestration.model.TranslationModuleConfig;
1012
import io.vavr.control.Option;
1113
import java.util.ArrayList;
1214
import javax.annotation.Nonnull;
@@ -37,14 +39,15 @@ static CompletionPostRequest toCompletionPostRequest(
3739
val moduleConfigs = toModuleConfigs(configCopy);
3840

3941
return CompletionPostRequest.create()
40-
.orchestrationConfig(OrchestrationConfig.create().moduleConfigurations(moduleConfigs))
41-
.inputParams(prompt.getTemplateParameters())
42+
.config(OrchestrationConfig.create().modules(moduleConfigs))
43+
.placeholderValues(prompt.getTemplateParameters())
4244
.messagesHistory(messageHistory);
4345
}
4446

4547
@Nonnull
46-
static TemplatingModuleConfig toTemplateModuleConfig(
47-
@Nonnull final OrchestrationPrompt prompt, @Nullable final TemplatingModuleConfig config) {
48+
static PromptTemplatingModuleConfigPrompt toTemplateModuleConfig(
49+
@Nonnull final OrchestrationPrompt prompt,
50+
@Nullable final PromptTemplatingModuleConfigPrompt config) {
4851
/*
4952
* Currently, we have to merge the prompt into the template configuration.
5053
* This works around the limitation that the template config is required.
@@ -89,16 +92,23 @@ static ModuleConfigs toModuleConfigs(@Nonnull final OrchestrationModuleConfig co
8992
//noinspection DataFlowIssue the template is always non-null here
9093
val moduleConfig =
9194
ModuleConfigs.create()
92-
.llmModuleConfig(llmConfig)
93-
.templatingModuleConfig(config.getTemplateConfig());
94-
95-
Option.of(config.getFilteringConfig()).forEach(moduleConfig::filteringModuleConfig);
96-
Option.of(config.getMaskingConfig()).forEach(moduleConfig::maskingModuleConfig);
97-
Option.of(config.getGroundingConfig()).forEach(moduleConfig::groundingModuleConfig);
98-
Option.of(config.getOutputTranslationConfig())
99-
.forEach(moduleConfig::outputTranslationModuleConfig);
100-
Option.of(config.getInputTranslationConfig())
101-
.forEach(moduleConfig::inputTranslationModuleConfig);
95+
.promptTemplating(
96+
PromptTemplatingModuleConfig.create()
97+
.prompt(config.getTemplateConfig())
98+
.model(llmConfig));
99+
100+
Option.of(config.getFilteringConfig()).forEach(moduleConfig::filtering);
101+
Option.of(config.getMaskingConfig()).forEach(moduleConfig::masking);
102+
Option.of(config.getGroundingConfig()).forEach(moduleConfig::grounding);
103+
104+
val outputTranslation = Option.of(config.getOutputTranslationConfig());
105+
val inputTranslation = Option.of(config.getInputTranslationConfig());
106+
107+
if (inputTranslation.isDefined() || outputTranslation.isDefined()) {
108+
moduleConfig.setTranslation(TranslationModuleConfig.create());
109+
inputTranslation.forEach(moduleConfig.getTranslation()::input);
110+
outputTranslation.forEach(moduleConfig.getTranslation()::output);
111+
}
102112

103113
return moduleConfig;
104114
}

orchestration/src/main/java/com/sap/ai/sdk/orchestration/Grounding.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import com.sap.ai.sdk.orchestration.model.GroundingModuleConfig.TypeEnum;
88
import com.sap.ai.sdk.orchestration.model.GroundingModuleConfigConfig;
99
import com.sap.ai.sdk.orchestration.model.GroundingModuleConfigConfigFiltersInner;
10+
import com.sap.ai.sdk.orchestration.model.GroundingModuleConfigConfigPlaceholders;
1011
import java.util.List;
1112
import java.util.Map;
1213
import javax.annotation.Nonnull;
@@ -81,8 +82,10 @@ public OrchestrationPrompt createGroundingPrompt(@Nonnull final String message)
8182
public GroundingModuleConfig createConfig() {
8283
val groundingConfigConfig =
8384
GroundingModuleConfigConfig.create()
84-
.inputParams(List.of("userMessage"))
85-
.outputParam("groundingContext")
85+
.placeholders(
86+
GroundingModuleConfigConfigPlaceholders.create()
87+
.input(List.of("userMessage"))
88+
.output("groundingContext"))
8689
.filters(filters);
8790

8891
if (filters.contains(

orchestration/src/main/java/com/sap/ai/sdk/orchestration/JacksonMixins.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package com.sap.ai.sdk.orchestration;
22

3+
import com.fasterxml.jackson.annotation.JsonAlias;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
35
import com.fasterxml.jackson.annotation.JsonSubTypes;
46
import com.fasterxml.jackson.annotation.JsonTypeInfo;
57
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
68
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
9+
import com.sap.ai.sdk.orchestration.model.AzureThreshold;
710
import com.sap.ai.sdk.orchestration.model.LLMModuleResult;
811
import lombok.AccessLevel;
912
import lombok.NoArgsConstructor;
@@ -56,4 +59,26 @@ interface ResponseFormatSubTypesMixin {}
5659
name = "user")
5760
})
5861
interface ChatMessageMixin {}
62+
63+
/**
64+
* Mixin used for parsing response "data" field of
65+
* error.intermediate_results.input_filtering.data.azure_content_safety
66+
*/
67+
abstract static class AzureContentSafetyCaseAgnostic {
68+
@JsonProperty("hate")
69+
@JsonAlias("Hate")
70+
private AzureThreshold hate;
71+
72+
@JsonProperty("self_harm")
73+
@JsonAlias("SelfHarm")
74+
private AzureThreshold selfHarm;
75+
76+
@JsonProperty("sexual")
77+
@JsonAlias("Sexual")
78+
private AzureThreshold sexual;
79+
80+
@JsonProperty("violence")
81+
@JsonAlias("Violence")
82+
private AzureThreshold violence;
83+
}
5984
}

orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationAiModel.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.sap.ai.sdk.orchestration;
22

3-
import com.sap.ai.sdk.orchestration.model.LLMModuleConfig;
3+
import com.sap.ai.sdk.orchestration.model.LLMModelDetails;
44
import java.util.LinkedHashMap;
55
import java.util.Map;
66
import javax.annotation.Nonnull;
@@ -276,8 +276,8 @@ public class OrchestrationAiModel {
276276
}
277277

278278
@Nonnull
279-
LLMModuleConfig createConfig() {
280-
return LLMModuleConfig.create().modelName(name).modelParams(params).modelVersion(version);
279+
LLMModelDetails createConfig() {
280+
return LLMModelDetails.create().name(name).params(params).version(version);
281281
}
282282

283283
/**

orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationChatCompletionDelta.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public class OrchestrationChatCompletionDelta extends CompletionPostResponseStre
1313
@Nonnull
1414
@Override
1515
public String getDeltaContent() {
16-
val choices = getOrchestrationResult().getChoices();
16+
val choices = getFinalResult().getChoices();
1717
// Avoid the first delta: "choices":[]
1818
if (!choices.isEmpty()
1919
// Multiple choices are spread out on multiple deltas
@@ -29,6 +29,6 @@ public String getDeltaContent() {
2929
@Nullable
3030
@Override
3131
public String getFinishReason() {
32-
return getOrchestrationResult().getChoices().get(0).getFinishReason();
32+
return getFinalResult().getChoices().get(0).getFinishReason();
3333
}
3434
}

orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationChatResponse.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public String getContent() throws OrchestrationFilterException.Output {
5151

5252
@SuppressWarnings("unchecked")
5353
private Map<String, Object> getOutputFilteringChoices() {
54-
final var f = getOriginalResponse().getModuleResults().getOutputFiltering();
54+
final var f = getOriginalResponse().getIntermediateResults().getOutputFiltering();
5555
return ((List<Map<String, Object>>) ((Map<String, Object>) f.getData()).get("choices")).get(0);
5656
}
5757

@@ -62,7 +62,7 @@ private Map<String, Object> getOutputFilteringChoices() {
6262
*/
6363
@Nonnull
6464
public TokenUsage getTokenUsage() {
65-
return originalResponse.getOrchestrationResult().getUsage();
65+
return originalResponse.getFinalResult().getUsage();
6666
}
6767

6868
/**
@@ -74,7 +74,8 @@ public TokenUsage getTokenUsage() {
7474
@Nonnull
7575
public List<Message> getAllMessages() throws IllegalArgumentException {
7676
val messages = new ArrayList<Message>();
77-
for (final ChatMessage chatMessage : originalResponse.getModuleResults().getTemplating()) {
77+
for (final ChatMessage chatMessage :
78+
originalResponse.getIntermediateResults().getTemplating()) {
7879
if (chatMessage instanceof AssistantChatMessage assistantChatMessage) {
7980
val toolCalls = assistantChatMessage.getToolCalls();
8081
if (!toolCalls.isEmpty()) {
@@ -115,7 +116,7 @@ public List<Message> getAllMessages() throws IllegalArgumentException {
115116
@Nonnull
116117
public LLMChoice getChoice() {
117118
// We expect choices to be defined and never empty.
118-
return originalResponse.getOrchestrationResult().getChoices().get(0);
119+
return originalResponse.getFinalResult().getChoices().get(0);
119120
}
120121

121122
/**
@@ -133,12 +134,7 @@ public LLMChoice getChoice() {
133134
@Nonnull
134135
public <T> T asEntity(@Nonnull final Class<T> type) throws OrchestrationClientException {
135136
final String refusal =
136-
getOriginalResponse()
137-
.getOrchestrationResult()
138-
.getChoices()
139-
.get(0)
140-
.getMessage()
141-
.getRefusal();
137+
getOriginalResponse().getFinalResult().getChoices().get(0).getMessage().getRefusal();
142138
if (refusal != null) {
143139
throw new OrchestrationClientException(
144140
"The model refused to answer the question: " + refusal);

0 commit comments

Comments
 (0)