From f1deedb16466318d321e35386556fa4423ea2de5 Mon Sep 17 00:00:00 2001 From: Jonas Israel Date: Wed, 15 Oct 2025 11:16:13 +0200 Subject: [PATCH 1/4] fix e2e tests --- .../app/services/OrchestrationService.java | 8 ++++-- .../ai/sdk/app/controllers/ScenarioTest.java | 25 +++++++++++++------ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java index d74a55bba..893c7b11f 100644 --- a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java +++ b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java @@ -443,12 +443,14 @@ public record Translation( @Nonnull public OrchestrationChatResponse responseFormatJsonSchema( @Nonnull final String word, @Nonnull final Class targetType) { + final var configWithGpt4 = + new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); val schema = ResponseJsonSchema.fromType(targetType) .withDescription("Output schema for language translation.") .withStrict(true); val configWithResponseSchema = - config.withTemplateConfig(TemplateConfig.create().withJsonSchemaResponse(schema)); + configWithGpt4.withTemplateConfig(TemplateConfig.create().withJsonSchemaResponse(schema)); val prompt = new OrchestrationPrompt( @@ -564,8 +566,10 @@ public OrchestrationChatResponse templateFromPromptRegistryByScenario( @Nonnull public OrchestrationChatResponse localPromptTemplate(@Nonnull final String promptTemplate) throws IOException { + final var configWithGpt4 = + new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); val template = TemplateConfig.create().fromYaml(promptTemplate); - val configWithTemplate = template != null ? config.withTemplateConfig(template) : config; + val configWithTemplate = template != null ? configWithGpt4.withTemplateConfig(template) : configWithGpt4; val inputParams = Map.of("language", "German"); val prompt = new OrchestrationPrompt(inputParams); diff --git a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/ScenarioTest.java b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/ScenarioTest.java index a2085e412..8c19a0305 100644 --- a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/ScenarioTest.java +++ b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/ScenarioTest.java @@ -8,7 +8,10 @@ import com.sap.ai.sdk.orchestration.OrchestrationAiModel; import java.lang.reflect.Field; import java.util.HashMap; +import java.util.HashSet; import java.util.Optional; +import java.util.Set; + import lombok.SneakyThrows; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayName; @@ -95,19 +98,27 @@ void orchestrationAiModelAvailability() { } } + // Set of internal-only models + var internalOnlyModels = Set.of("abap-codestral"); + // Assert that the declared Orchestration models match the expected list - assertThat(declaredOrchestrationModelList.keySet()) + var declaredAndInternalOnlyModels = new HashSet<>(declaredOrchestrationModelList.keySet()); + declaredAndInternalOnlyModels.addAll(internalOnlyModels); + + assertThat(declaredAndInternalOnlyModels) .containsAll(availableOrchestrationModels.keySet()); SoftAssertions softly = new SoftAssertions(); for (var model : availableOrchestrationModels.entrySet()) { Boolean declaredDeprecated = declaredOrchestrationModelList.get(model.getKey()); - softly - .assertThat(declaredDeprecated) - .withFailMessage( - "%s is deprecated:%s on AI Core but deprecated:%s in AI SDK", - model.getKey(), model.getValue(), declaredDeprecated) - .isEqualTo(model.getValue()); + if (!internalOnlyModels.contains(model.getKey())) { + softly + .assertThat(declaredDeprecated) + .withFailMessage( + "%s is deprecated:%s on AI Core but deprecated:%s in AI SDK", + model.getKey(), model.getValue(), declaredDeprecated) + .isEqualTo(model.getValue()); + } } softly.assertAll(); } From 8dd1809d685fc0e76a002d9c721cb08d0928a36a Mon Sep 17 00:00:00 2001 From: Jonas Israel Date: Wed, 15 Oct 2025 15:31:07 +0200 Subject: [PATCH 2/4] codestyle --- .../sap/ai/sdk/app/services/OrchestrationService.java | 9 ++++----- .../com/sap/ai/sdk/app/controllers/ScenarioTest.java | 4 +--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java index de71701a4..a0925ebeb 100644 --- a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java +++ b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java @@ -465,8 +465,7 @@ public record Translation( @Nonnull public OrchestrationChatResponse responseFormatJsonSchema( @Nonnull final String word, @Nonnull final Class targetType) { - final var configWithGpt4 = - new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); + final var configWithGpt4 = new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); val schema = ResponseJsonSchema.fromType(targetType) .withDescription("Output schema for language translation.") @@ -588,10 +587,10 @@ public OrchestrationChatResponse templateFromPromptRegistryByScenario( @Nonnull public OrchestrationChatResponse localPromptTemplate(@Nonnull final String promptTemplate) throws IOException { - final var configWithGpt4 = - new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); + final var configWithGpt4 = new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); val template = TemplateConfig.create().fromYaml(promptTemplate); - val configWithTemplate = template != null ? configWithGpt4.withTemplateConfig(template) : configWithGpt4; + val configWithTemplate = + template != null ? configWithGpt4.withTemplateConfig(template) : configWithGpt4; val inputParams = Map.of("language", "German"); val prompt = new OrchestrationPrompt(inputParams); diff --git a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/ScenarioTest.java b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/ScenarioTest.java index 8c19a0305..dac8901e3 100644 --- a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/ScenarioTest.java +++ b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/ScenarioTest.java @@ -11,7 +11,6 @@ import java.util.HashSet; import java.util.Optional; import java.util.Set; - import lombok.SneakyThrows; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.DisplayName; @@ -105,8 +104,7 @@ void orchestrationAiModelAvailability() { var declaredAndInternalOnlyModels = new HashSet<>(declaredOrchestrationModelList.keySet()); declaredAndInternalOnlyModels.addAll(internalOnlyModels); - assertThat(declaredAndInternalOnlyModels) - .containsAll(availableOrchestrationModels.keySet()); + assertThat(declaredAndInternalOnlyModels).containsAll(availableOrchestrationModels.keySet()); SoftAssertions softly = new SoftAssertions(); for (var model : availableOrchestrationModels.entrySet()) { From f9df55d241442480cff30881c8a9030d731600fc Mon Sep 17 00:00:00 2001 From: Jonas Israel Date: Thu, 16 Oct 2025 13:22:41 +0200 Subject: [PATCH 3/4] simplify test --- .../ai/sdk/app/controllers/ScenarioTest.java | 27 ++++++++----------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/ScenarioTest.java b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/ScenarioTest.java index dac8901e3..767c88f28 100644 --- a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/ScenarioTest.java +++ b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/ScenarioTest.java @@ -8,7 +8,6 @@ import com.sap.ai.sdk.orchestration.OrchestrationAiModel; import java.lang.reflect.Field; import java.util.HashMap; -import java.util.HashSet; import java.util.Optional; import java.util.Set; import lombok.SneakyThrows; @@ -72,6 +71,8 @@ void orchestrationAiModelAvailability() { // Gather AI Core's list of available Orchestration models final var aiModelList = new ScenarioController().getModels().getResources(); + var internalOnlyModels = Set.of("abap-codestral"); + final var availableOrchestrationModels = aiModelList.stream() .filter( @@ -79,6 +80,7 @@ void orchestrationAiModelAvailability() { model.getAllowedScenarios().stream() .anyMatch(scenario -> scenario.getScenarioId().equals("orchestration"))) .filter(model -> !model.getModel().contains("embed")) + .filter(model -> !internalOnlyModels.contains(model.getModel())) .collect( () -> new HashMap(), (list, model) -> list.put(model.getModel(), isDeprecated(model)), @@ -97,26 +99,19 @@ void orchestrationAiModelAvailability() { } } - // Set of internal-only models - var internalOnlyModels = Set.of("abap-codestral"); - // Assert that the declared Orchestration models match the expected list - var declaredAndInternalOnlyModels = new HashSet<>(declaredOrchestrationModelList.keySet()); - declaredAndInternalOnlyModels.addAll(internalOnlyModels); - - assertThat(declaredAndInternalOnlyModels).containsAll(availableOrchestrationModels.keySet()); + assertThat(declaredOrchestrationModelList.keySet()) + .containsAll(availableOrchestrationModels.keySet()); SoftAssertions softly = new SoftAssertions(); for (var model : availableOrchestrationModels.entrySet()) { Boolean declaredDeprecated = declaredOrchestrationModelList.get(model.getKey()); - if (!internalOnlyModels.contains(model.getKey())) { - softly - .assertThat(declaredDeprecated) - .withFailMessage( - "%s is deprecated:%s on AI Core but deprecated:%s in AI SDK", - model.getKey(), model.getValue(), declaredDeprecated) - .isEqualTo(model.getValue()); - } + softly + .assertThat(declaredDeprecated) + .withFailMessage( + "%s is deprecated:%s on AI Core but deprecated:%s in AI SDK", + model.getKey(), model.getValue(), declaredDeprecated) + .isEqualTo(model.getValue()); } softly.assertAll(); } From b6d9e1455b3e230cc55700a42978748c903c4660 Mon Sep 17 00:00:00 2001 From: Jonas Israel Date: Thu, 16 Oct 2025 13:45:18 +0200 Subject: [PATCH 4/4] add note on orch bug --- .../com/sap/ai/sdk/app/services/OrchestrationService.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java index a0925ebeb..85943bcd0 100644 --- a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java +++ b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java @@ -465,6 +465,8 @@ public record Translation( @Nonnull public OrchestrationChatResponse responseFormatJsonSchema( @Nonnull final String word, @Nonnull final Class targetType) { + // Gemini cannot be used here. This is a known issue that should be resolved with AI Core + // release 2510b. See https://jira.tools.sap/browse/AI-125770 final var configWithGpt4 = new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); val schema = ResponseJsonSchema.fromType(targetType) @@ -587,6 +589,8 @@ public OrchestrationChatResponse templateFromPromptRegistryByScenario( @Nonnull public OrchestrationChatResponse localPromptTemplate(@Nonnull final String promptTemplate) throws IOException { + // Gemini cannot be used here. This is a known issue that should be resolved with AI Core + // release 2510b. See https://jira.tools.sap/browse/AI-125770 final var configWithGpt4 = new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); val template = TemplateConfig.create().fromYaml(promptTemplate); val configWithTemplate =