From 9614895fb46fd8e2533c02158dceb04b346929e5 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Wed, 25 Feb 2026 10:48:25 +0100 Subject: [PATCH 01/32] full implementation --- .../TranslationApplyToSelector.java | 115 ++++++++++++++++++ .../sdk/orchestration/TranslationConfig.java | 18 ++- .../OrchestrationModuleConfigTest.java | 40 ++++++ .../app/services/OrchestrationService.java | 31 +++-- .../app/controllers/OrchestrationTest.java | 19 +-- 5 files changed, 201 insertions(+), 22 deletions(-) create mode 100644 orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationApplyToSelector.java diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationApplyToSelector.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationApplyToSelector.java new file mode 100644 index 000000000..bbec39983 --- /dev/null +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationApplyToSelector.java @@ -0,0 +1,115 @@ +package com.sap.ai.sdk.orchestration; + +import static com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector.CategoryEnum.PLACEHOLDERS; +import static com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector.CategoryEnum.TEMPLATE_ROLES; + +import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import javax.annotation.Nonnull; + +/** + * Convenience builder for {@link SAPDocumentTranslationApplyToSelector}. + * + *

This avoids passing raw strings for template roles and keeps sample-code readable. + */ +public final class TranslationApplyToSelector { + private TranslationApplyToSelector() {} + + /** + * Supported values for {@code items[]} when {@code category=template_roles}. + * + *

These map to the roles used in prompt templates. + */ + public enum TemplateRole { + /** Template role for user messages. */ + USER("user"), + + /** Template role for system messages. */ + SYSTEM("system"), + + /** Template role for assistant messages. */ + ASSISTANT("assistant"), + + /** Template role for developer messages. */ + DEVELOPER("developer"), + + /** Template role for tool messages. */ + TOOL("tool"); + + private final String value; + + TemplateRole(@Nonnull final String value) { + this.value = value; + } + + /** + * Get the string representation used in the API payload. + * + * @return The role value used in {@code items[]}. + */ + @Nonnull + public String getValue() { + return value; + } + } + + /** + * Start an {@code apply_to} selector for placeholder names in {@code placeholder_values}. + * + * @param names The placeholder keys to translate. + * @return A selector with {@code category=placeholders} and the given items. + */ + @Nonnull + public static SAPDocumentTranslationApplyToSelector placeholders(@Nonnull final String... names) { + Objects.requireNonNull(names, "names must not be null"); + return placeholders(List.of(names)); + } + + /** + * Start an {@code apply_to} selector for placeholder names in {@code placeholder_values}. + * + * @param names The placeholder keys to translate. + * @return A selector with {@code category=placeholders} and the given items. + */ + @Nonnull + public static SAPDocumentTranslationApplyToSelector placeholders( + @Nonnull final List names) { + Objects.requireNonNull(names, "names must not be null"); + return SAPDocumentTranslationApplyToSelector.create() + .category(PLACEHOLDERS) + .items(List.copyOf(names)); + } + + /** + * Start an {@code apply_to} selector for prompt template message roles. + * + * @param roles The template roles to translate. + * @return A selector with {@code category=template_roles} and the given items. + */ + @Nonnull + public static SAPDocumentTranslationApplyToSelector templateRoles( + @Nonnull final TemplateRole... roles) { + Objects.requireNonNull(roles, "roles must not be null"); + return templateRoles(List.of(roles)); + } + + /** + * Start an {@code apply_to} selector for prompt template message roles. + * + * @param roles The template roles to translate. + * @return A selector with {@code category=template_roles} and the given items. + */ + @Nonnull + public static SAPDocumentTranslationApplyToSelector templateRoles( + @Nonnull final Collection roles) { + Objects.requireNonNull(roles, "roles must not be null"); + final var roleStrings = + roles.stream().filter(Objects::nonNull).map(TemplateRole::getValue).toList(); + + return SAPDocumentTranslationApplyToSelector.create() + .category(TEMPLATE_ROLES) + .items(roleStrings); + } +} diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index 6210f6f7a..f830bd895 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -1,10 +1,12 @@ package com.sap.ai.sdk.orchestration; +import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector; import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationInput; import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationInputConfig; import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutput; import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutputConfig; import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutputTargetLanguage; +import java.util.List; import javax.annotation.Nonnull; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; @@ -29,13 +31,21 @@ class Input implements TranslationConfig { @With String sourceLanguage; - Object ApplyTo; // Can be null + /** + * Optional selection(s) to translate. If empty or null, translation is applied to the whole + * user input. + */ + @With List applyTo; @Nonnull SAPDocumentTranslationInput createSAPDocumentTranslationInput() { val translationType = SAPDocumentTranslationInput.TypeEnum.SAP_DOCUMENT_TRANSLATION; - val conf = - SAPDocumentTranslationInputConfig.create().targetLanguage(targetLanguage).applyTo(null); + final var conf = SAPDocumentTranslationInputConfig.create().targetLanguage(targetLanguage); + + if (applyTo != null && !applyTo.isEmpty()) { + conf.applyTo(applyTo); + } + return SAPDocumentTranslationInput.create().type(translationType).config(conf); } } @@ -71,7 +81,6 @@ SAPDocumentTranslationOutput createSAPDocumentTranslationOutput() { */ @Nonnull static TranslationConfig.Input translateInputTo(@Nonnull final String targetLanguage) { - return new TranslationConfig.Input(targetLanguage, null, null); } @@ -86,7 +95,6 @@ static TranslationConfig.Input translateInputTo(@Nonnull final String targetLang */ @Nonnull static TranslationConfig.Output translateOutputTo(@Nonnull final String targetLanguage) { - return new TranslationConfig.Output(targetLanguage, null); } } diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java index fcbeaed33..a47bd9e02 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java @@ -175,6 +175,46 @@ void testTranslationConfig() { .getSourceLanguage()); } + @Test + void testTranslationConfigApplyToSelectors() { + var selector = + TranslationApplyToSelector.placeholders("exam_type", "topic").sourceLanguage("de-DE"); + + final var inputTranslationConfig = + TranslationConfig.translateInputTo("en-US").withApplyTo(List.of(selector)); + + final var sapInput = inputTranslationConfig.createSAPDocumentTranslationInput(); + assertThat(sapInput.getConfig().getTargetLanguage()).isEqualTo("en-US"); + assertThat(sapInput.getConfig().getApplyTo()).hasSize(1); + assertThat(sapInput.getConfig().getApplyTo().get(0).getCategory().getValue()) + .isEqualTo("placeholders"); + assertThat(sapInput.getConfig().getApplyTo().get(0).getItems()) + .containsExactly("exam_type", "topic"); + + final var inputNull = TranslationConfig.translateInputTo("en-US"); + final var sapNull = inputNull.createSAPDocumentTranslationInput(); + assertThat(sapNull.getConfig().getApplyTo()).isEmpty(); + + // applyTo == empty list + final var inputEmpty = TranslationConfig.translateInputTo("en-US").withApplyTo(List.of()); + final var sapEmpty = inputEmpty.createSAPDocumentTranslationInput(); + assertThat(sapEmpty.getConfig().getApplyTo()).isEmpty(); + + selector = + TranslationApplyToSelector.templateRoles( + TranslationApplyToSelector.TemplateRole.USER, + TranslationApplyToSelector.TemplateRole.SYSTEM, + TranslationApplyToSelector.TemplateRole.ASSISTANT, + TranslationApplyToSelector.TemplateRole.DEVELOPER, + TranslationApplyToSelector.TemplateRole.TOOL) + .sourceLanguage("de-DE"); + + assertThat(selector.getCategory().getValue()).isEqualTo("template_roles"); + assertThat(selector.getItems()) + .containsExactly("user", "system", "assistant", "developer", "tool"); + assertThat(selector.getSourceLanguage()).isEqualTo("de-DE"); + } + @Test void testParams() { // test withParams(Map) 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 9c7890feb..e078cdacf 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 @@ -28,6 +28,7 @@ import com.sap.ai.sdk.orchestration.ResponseJsonSchema; import com.sap.ai.sdk.orchestration.SystemMessage; import com.sap.ai.sdk.orchestration.TemplateConfig; +import com.sap.ai.sdk.orchestration.TranslationApplyToSelector; import com.sap.ai.sdk.orchestration.TranslationConfig; import com.sap.ai.sdk.orchestration.model.DPIEntities; import com.sap.ai.sdk.orchestration.model.DataRepositoryType; @@ -681,17 +682,31 @@ public OrchestrationChatResponse localPromptTemplate(@Nonnull final String promp */ @Nonnull public OrchestrationChatResponse translation() { - val prompt = - new OrchestrationPrompt( - "Quelle est la couleur de la tour Eiffel? Et en quelle langue tu me parles maintenant?"); - // list of supported language pairs - // https://help.sap.com/docs/translation-hub/sap-translation-hub/supported-languages?version=Cloud#translation-provider-sap-machine-translation + val inputParams = + Map.of("exam_type", "Abitur", "topic", "Deutsche Literatur", "num_questions", "5"); + + val systemMessage = + Message.system( + "You are an expert study coach creating clear, concise exam notes and practice questions."); + val userMessage = + Message.user( + "Generate a study guide for the {{?exam_type}} exam on {{?topic}}.\n\nInclude {{?num_questions}} practice questions."); + val templatingConfig = TemplateConfig.create().withMessages(systemMessage, userMessage); + + val prompt = new OrchestrationPrompt(inputParams); + val configWithTranslation = config - .withInputTranslationConfig(TranslationConfig.translateInputTo("en-US")) + .withTemplateConfig(templatingConfig) + .withInputTranslationConfig( + TranslationConfig.translateInputTo("en-US") + .withApplyTo( + List.of( + // Translate only selected placeholder values from German to English + TranslationApplyToSelector.placeholders(List.of("exam_type", "topic")) + .sourceLanguage("de-DE")))) .withOutputTranslationConfig( - TranslationConfig.translateOutputTo("de-DE") - .withSourceLanguage("en-US")); // optional source language + TranslationConfig.translateOutputTo("de-DE").withSourceLanguage("en-US")); return client.chatCompletion(prompt, configWithTranslation); } diff --git a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java index 5051e091c..ca7906b3d 100644 --- a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java +++ b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java @@ -22,7 +22,6 @@ import com.sap.ai.sdk.orchestration.TemplateConfig; import com.sap.ai.sdk.orchestration.TextItem; import com.sap.ai.sdk.orchestration.model.DPIEntities; -import com.sap.ai.sdk.orchestration.model.GenericModuleResult; import com.sap.ai.sdk.orchestration.model.InputTranslationModuleResult; import java.io.IOException; import java.io.InputStream; @@ -225,7 +224,7 @@ void testGroundingSharepoint() { assertThat(response).isNotNull(); var result = response.getOriginalResponse(); var llmChoice = result.getFinalResult().getChoices().get(0); - assertThat(llmChoice.getMessage().getContent()).contains("&)UPnkL_izT)&1u%?2Kg*Y.@qFqR@/"); + assertThat(llmChoice.getMessage().getContent()).contains("&)UPNkL_izT)&1u%?2Kg*Y.@qFqR@/"); } @Test @@ -496,18 +495,20 @@ void testStreamingErrorHandlingMasking() { void testTranslation() { val result = service.translation(); val content = result.getContent(); - // English translated to German - assertThat(content).contains("Englisch"); - assertThat(content).contains("Der", "ist"); + // Output translation turns the model response back to German + assertThat(content) + .containsAnyOf("Abitur", "Deutsche", "Literatur", "Lern", "Übungs", "Fragen"); InputTranslationModuleResult inputTranslation = result.getOriginalResponse().getIntermediateResults().getInputTranslation(); - GenericModuleResult outputTranslation = - result.getOriginalResponse().getIntermediateResults().getOutputTranslation(); assertThat(inputTranslation).isNotNull(); - assertThat(outputTranslation).isNotNull(); assertThat(inputTranslation.getMessage()) - .isEqualTo("Translated messages with roles: ['user']. "); + .isNotNull() + .contains("Successfully translated placeholders: ['exam_type', 'topic']. "); + + val outputTranslation = + result.getOriginalResponse().getIntermediateResults().getOutputTranslation(); + assertThat(outputTranslation).isNotNull(); assertThat(outputTranslation.getMessage()).isEqualTo("Output Translation successful"); } From 3aec367cf6fa7a1a900e911135c106dfa288c8ab Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Wed, 25 Feb 2026 11:06:35 +0100 Subject: [PATCH 02/32] release notes --- docs/release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release_notes.md b/docs/release_notes.md index 80e2325c3..b9af822c7 100644 --- a/docs/release_notes.md +++ b/docs/release_notes.md @@ -16,7 +16,7 @@ ### 📈 Improvements -- +- [Orchestration] Added new API `TranslationConfig#withApplyTo` to support partial translation for user's input. ### 🐛 Fixed Issues From a429f3780a49c2f1136eb1b53573edeb3014e5a9 Mon Sep 17 00:00:00 2001 From: Nourhan Islam Shata <163640161+n-o-u-r-h-a-n@users.noreply.github.com> Date: Wed, 25 Feb 2026 11:58:51 +0100 Subject: [PATCH 03/32] Update sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java Co-authored-by: Charles Dubois <103174266+CharlesDuboisSAP@users.noreply.github.com> --- .../java/com/sap/ai/sdk/app/services/OrchestrationService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 895e970e2..fb6c62fb6 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 @@ -711,7 +711,7 @@ public OrchestrationChatResponse translation() { List.of( // Translate only selected placeholder values from German to English TranslationApplyToSelector.placeholders(List.of("exam_type", "topic")) - .sourceLanguage("de-DE")))) + )).withSourceLanguage("de-DE")) .withOutputTranslationConfig( TranslationConfig.translateOutputTo("de-DE").withSourceLanguage("en-US")); From 46230db51252358ba407d43d70feccc10e5b6872 Mon Sep 17 00:00:00 2001 From: SAP Cloud SDK Bot Date: Wed, 25 Feb 2026 10:59:41 +0000 Subject: [PATCH 04/32] Formatting --- .../com/sap/ai/sdk/app/services/OrchestrationService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 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 fb6c62fb6..defb1599e 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 @@ -710,8 +710,8 @@ public OrchestrationChatResponse translation() { .withApplyTo( List.of( // Translate only selected placeholder values from German to English - TranslationApplyToSelector.placeholders(List.of("exam_type", "topic")) - )).withSourceLanguage("de-DE")) + TranslationApplyToSelector.placeholders(List.of("exam_type", "topic")))) + .withSourceLanguage("de-DE")) .withOutputTranslationConfig( TranslationConfig.translateOutputTo("de-DE").withSourceLanguage("en-US")); From fdf7a5e00477d5492be756d45103191ffd7fb679 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Wed, 25 Feb 2026 12:07:20 +0100 Subject: [PATCH 05/32] reverting --- .../com/sap/ai/sdk/app/controllers/OrchestrationTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java index d3a9b8f73..7762c7239 100644 --- a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java +++ b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java @@ -224,7 +224,7 @@ void testGroundingSharepoint() { assertThat(response).isNotNull(); var result = response.getOriginalResponse(); var llmChoice = result.getFinalResult().getChoices().get(0); - assertThat(llmChoice.getMessage().getContent()).contains("&)UPNkL_izT)&1u%?2Kg*Y.@qFqR@/"); + assertThat(llmChoice.getMessage().getContent()).contains("&)UPnkL_izT)&1u%?2Kg*Y.@qFqR@/"); } @Test @@ -505,7 +505,7 @@ void testTranslation() { assertThat(inputTranslation).isNotNull(); assertThat(inputTranslation.getMessage()) .isNotNull() - .contains("Successfully translated placeholders: ['exam_type', 'topic']. "); + .contains("Successfully translated placeholders: ['exam_type', 'topic']. "); val outputTranslation = result.getOriginalResponse().getIntermediateResults().getOutputTranslation(); From 5b8e5367722409fd63df7670c90da4bb0c119d37 Mon Sep 17 00:00:00 2001 From: SAP Cloud SDK Bot Date: Wed, 25 Feb 2026 11:08:19 +0000 Subject: [PATCH 06/32] Formatting --- .../java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java index 7762c7239..c17d0ff20 100644 --- a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java +++ b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java @@ -505,7 +505,7 @@ void testTranslation() { assertThat(inputTranslation).isNotNull(); assertThat(inputTranslation.getMessage()) .isNotNull() - .contains("Successfully translated placeholders: ['exam_type', 'topic']. "); + .contains("Successfully translated placeholders: ['exam_type', 'topic']. "); val outputTranslation = result.getOriginalResponse().getIntermediateResults().getOutputTranslation(); From 9a5a2002322b074abe171018c4922b1c80d4c0b0 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Wed, 25 Feb 2026 12:16:08 +0100 Subject: [PATCH 07/32] refactoring the new class name --- ...ranslationApplyToSelector.java => ApplyTo.java} | 4 ++-- .../OrchestrationModuleConfigTest.java | 14 +++++++------- .../ai/sdk/app/services/OrchestrationService.java | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) rename orchestration/src/main/java/com/sap/ai/sdk/orchestration/{TranslationApplyToSelector.java => ApplyTo.java} (97%) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationApplyToSelector.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java similarity index 97% rename from orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationApplyToSelector.java rename to orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java index bbec39983..9c956195c 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationApplyToSelector.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java @@ -14,8 +14,8 @@ * *

This avoids passing raw strings for template roles and keeps sample-code readable. */ -public final class TranslationApplyToSelector { - private TranslationApplyToSelector() {} +public final class ApplyTo { + private ApplyTo() {} /** * Supported values for {@code items[]} when {@code category=template_roles}. diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java index 995e6a3a8..ae6803114 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java @@ -179,7 +179,7 @@ void testTranslationConfig() { @Test void testTranslationConfigApplyToSelectors() { var selector = - TranslationApplyToSelector.placeholders("exam_type", "topic").sourceLanguage("de-DE"); + ApplyTo.placeholders("exam_type", "topic").sourceLanguage("de-DE"); final var inputTranslationConfig = TranslationConfig.translateInputTo("en-US").withApplyTo(List.of(selector)); @@ -202,12 +202,12 @@ void testTranslationConfigApplyToSelectors() { assertThat(sapEmpty.getConfig().getApplyTo()).isEmpty(); selector = - TranslationApplyToSelector.templateRoles( - TranslationApplyToSelector.TemplateRole.USER, - TranslationApplyToSelector.TemplateRole.SYSTEM, - TranslationApplyToSelector.TemplateRole.ASSISTANT, - TranslationApplyToSelector.TemplateRole.DEVELOPER, - TranslationApplyToSelector.TemplateRole.TOOL) + ApplyTo.templateRoles( + ApplyTo.TemplateRole.USER, + ApplyTo.TemplateRole.SYSTEM, + ApplyTo.TemplateRole.ASSISTANT, + ApplyTo.TemplateRole.DEVELOPER, + ApplyTo.TemplateRole.TOOL) .sourceLanguage("de-DE"); assertThat(selector.getCategory().getValue()).isEqualTo("template_roles"); 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 defb1599e..330a4533f 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 @@ -28,7 +28,7 @@ import com.sap.ai.sdk.orchestration.ResponseJsonSchema; import com.sap.ai.sdk.orchestration.SystemMessage; import com.sap.ai.sdk.orchestration.TemplateConfig; -import com.sap.ai.sdk.orchestration.TranslationApplyToSelector; +import com.sap.ai.sdk.orchestration.ApplyTo; import com.sap.ai.sdk.orchestration.TranslationConfig; import com.sap.ai.sdk.orchestration.model.DPIEntities; import com.sap.ai.sdk.orchestration.model.DataRepositoryType; @@ -710,7 +710,7 @@ public OrchestrationChatResponse translation() { .withApplyTo( List.of( // Translate only selected placeholder values from German to English - TranslationApplyToSelector.placeholders(List.of("exam_type", "topic")))) + ApplyTo.placeholders(List.of("exam_type", "topic")))) .withSourceLanguage("de-DE")) .withOutputTranslationConfig( TranslationConfig.translateOutputTo("de-DE").withSourceLanguage("en-US")); From d3cf79d7db436e2a059a7889752801be4e7021ce Mon Sep 17 00:00:00 2001 From: SAP Cloud SDK Bot Date: Wed, 25 Feb 2026 11:16:57 +0000 Subject: [PATCH 08/32] Formatting --- .../ai/sdk/orchestration/OrchestrationModuleConfigTest.java | 3 +-- .../java/com/sap/ai/sdk/app/services/OrchestrationService.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java index ae6803114..4e21555fc 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java @@ -178,8 +178,7 @@ void testTranslationConfig() { @Test void testTranslationConfigApplyToSelectors() { - var selector = - ApplyTo.placeholders("exam_type", "topic").sourceLanguage("de-DE"); + var selector = ApplyTo.placeholders("exam_type", "topic").sourceLanguage("de-DE"); final var inputTranslationConfig = TranslationConfig.translateInputTo("en-US").withApplyTo(List.of(selector)); 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 330a4533f..4076958ad 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 @@ -9,6 +9,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.sap.ai.sdk.core.AiCoreService; +import com.sap.ai.sdk.orchestration.ApplyTo; import com.sap.ai.sdk.orchestration.AzureContentFilter; import com.sap.ai.sdk.orchestration.AzureFilterThreshold; import com.sap.ai.sdk.orchestration.DpiMasking; @@ -28,7 +29,6 @@ import com.sap.ai.sdk.orchestration.ResponseJsonSchema; import com.sap.ai.sdk.orchestration.SystemMessage; import com.sap.ai.sdk.orchestration.TemplateConfig; -import com.sap.ai.sdk.orchestration.ApplyTo; import com.sap.ai.sdk.orchestration.TranslationConfig; import com.sap.ai.sdk.orchestration.model.DPIEntities; import com.sap.ai.sdk.orchestration.model.DataRepositoryType; From dc21aea8e9069f95c6cc026e5254b144f359991d Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Wed, 25 Feb 2026 12:35:18 +0100 Subject: [PATCH 09/32] reverting a comment --- .../java/com/sap/ai/sdk/app/services/OrchestrationService.java | 2 ++ 1 file changed, 2 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 330a4533f..99f0f67b9 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 @@ -701,6 +701,8 @@ public OrchestrationChatResponse translation() { val templatingConfig = TemplateConfig.create().withMessages(systemMessage, userMessage); val prompt = new OrchestrationPrompt(inputParams); + // list of supported language pairs + // https://help.sap.com/docs/translation-hub/sap-translation-hub/supported-languages?version=Cloud#translation-provider-sap-machine-translation val configWithTranslation = config From 0fb1bc3a8cb434827504083054d63941d505dc49 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Wed, 25 Feb 2026 13:04:25 +0100 Subject: [PATCH 10/32] fixed test + reduced methods --- .../com/sap/ai/sdk/orchestration/ApplyTo.java | 34 +++---------------- .../app/services/OrchestrationService.java | 2 +- .../app/controllers/OrchestrationTest.java | 4 ++- 3 files changed, 8 insertions(+), 32 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java index 9c956195c..05627b1d5 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java @@ -4,6 +4,8 @@ import static com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector.CategoryEnum.TEMPLATE_ROLES; import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector; +import lombok.Getter; + import java.util.Collection; import java.util.List; import java.util.Objects; @@ -38,21 +40,11 @@ public enum TemplateRole { /** Template role for tool messages. */ TOOL("tool"); - private final String value; + @Getter private final String value; TemplateRole(@Nonnull final String value) { this.value = value; } - - /** - * Get the string representation used in the API payload. - * - * @return The role value used in {@code items[]}. - */ - @Nonnull - public String getValue() { - return value; - } } /** @@ -63,23 +55,7 @@ public String getValue() { */ @Nonnull public static SAPDocumentTranslationApplyToSelector placeholders(@Nonnull final String... names) { - Objects.requireNonNull(names, "names must not be null"); - return placeholders(List.of(names)); - } - - /** - * Start an {@code apply_to} selector for placeholder names in {@code placeholder_values}. - * - * @param names The placeholder keys to translate. - * @return A selector with {@code category=placeholders} and the given items. - */ - @Nonnull - public static SAPDocumentTranslationApplyToSelector placeholders( - @Nonnull final List names) { - Objects.requireNonNull(names, "names must not be null"); - return SAPDocumentTranslationApplyToSelector.create() - .category(PLACEHOLDERS) - .items(List.copyOf(names)); + return SAPDocumentTranslationApplyToSelector.create().category(PLACEHOLDERS).items(names); } /** @@ -91,7 +67,6 @@ public static SAPDocumentTranslationApplyToSelector placeholders( @Nonnull public static SAPDocumentTranslationApplyToSelector templateRoles( @Nonnull final TemplateRole... roles) { - Objects.requireNonNull(roles, "roles must not be null"); return templateRoles(List.of(roles)); } @@ -104,7 +79,6 @@ public static SAPDocumentTranslationApplyToSelector templateRoles( @Nonnull public static SAPDocumentTranslationApplyToSelector templateRoles( @Nonnull final Collection roles) { - Objects.requireNonNull(roles, "roles must not be null"); final var roleStrings = roles.stream().filter(Objects::nonNull).map(TemplateRole::getValue).toList(); 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 b39f9b4b1..fdbe3c326 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 @@ -712,7 +712,7 @@ public OrchestrationChatResponse translation() { .withApplyTo( List.of( // Translate only selected placeholder values from German to English - ApplyTo.placeholders(List.of("exam_type", "topic")))) + ApplyTo.placeholders("exam_type", "topic"))) .withSourceLanguage("de-DE")) .withOutputTranslationConfig( TranslationConfig.translateOutputTo("de-DE").withSourceLanguage("en-US")); diff --git a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java index c17d0ff20..0b2ada3c4 100644 --- a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java +++ b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OrchestrationTest.java @@ -505,7 +505,9 @@ void testTranslation() { assertThat(inputTranslation).isNotNull(); assertThat(inputTranslation.getMessage()) .isNotNull() - .contains("Successfully translated placeholders: ['exam_type', 'topic']. "); + .contains("Successfully translated placeholders:") + .contains("exam_type") + .contains("topic"); val outputTranslation = result.getOriginalResponse().getIntermediateResults().getOutputTranslation(); From 20b4c27ab92482a07913dcedcdffe28f00b8932b Mon Sep 17 00:00:00 2001 From: SAP Cloud SDK Bot Date: Wed, 25 Feb 2026 12:05:23 +0000 Subject: [PATCH 11/32] Formatting --- .../src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java index 05627b1d5..0be8923b7 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java @@ -4,12 +4,11 @@ import static com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector.CategoryEnum.TEMPLATE_ROLES; import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector; -import lombok.Getter; - import java.util.Collection; import java.util.List; import java.util.Objects; import javax.annotation.Nonnull; +import lombok.Getter; /** * Convenience builder for {@link SAPDocumentTranslationApplyToSelector}. From 7918494ac3483201798135841e52b959ef8802a6 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Wed, 25 Feb 2026 13:53:20 +0100 Subject: [PATCH 12/32] further method reduction --- .../com/sap/ai/sdk/orchestration/ApplyTo.java | 15 ++------------- .../OrchestrationModuleConfigTest.java | 13 ++++++------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java index 05627b1d5..e87bdd8b7 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java @@ -9,6 +9,7 @@ import java.util.Collection; import java.util.List; import java.util.Objects; +import java.util.stream.Stream; import javax.annotation.Nonnull; /** @@ -67,20 +68,8 @@ public static SAPDocumentTranslationApplyToSelector placeholders(@Nonnull final @Nonnull public static SAPDocumentTranslationApplyToSelector templateRoles( @Nonnull final TemplateRole... roles) { - return templateRoles(List.of(roles)); - } - - /** - * Start an {@code apply_to} selector for prompt template message roles. - * - * @param roles The template roles to translate. - * @return A selector with {@code category=template_roles} and the given items. - */ - @Nonnull - public static SAPDocumentTranslationApplyToSelector templateRoles( - @Nonnull final Collection roles) { final var roleStrings = - roles.stream().filter(Objects::nonNull).map(TemplateRole::getValue).toList(); + Stream.of(roles).filter(Objects::nonNull).map(TemplateRole::getValue).toList(); return SAPDocumentTranslationApplyToSelector.create() .category(TEMPLATE_ROLES) diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java index 4e21555fc..639e288e5 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java @@ -1,5 +1,10 @@ package com.sap.ai.sdk.orchestration; +import static com.sap.ai.sdk.orchestration.ApplyTo.TemplateRole.ASSISTANT; +import static com.sap.ai.sdk.orchestration.ApplyTo.TemplateRole.DEVELOPER; +import static com.sap.ai.sdk.orchestration.ApplyTo.TemplateRole.SYSTEM; +import static com.sap.ai.sdk.orchestration.ApplyTo.TemplateRole.TOOL; +import static com.sap.ai.sdk.orchestration.ApplyTo.TemplateRole.USER; import static com.sap.ai.sdk.orchestration.AzureFilterThreshold.ALLOW_SAFE_LOW_MEDIUM; import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.GPT_4O; import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.Parameter.MAX_TOKENS; @@ -201,13 +206,7 @@ void testTranslationConfigApplyToSelectors() { assertThat(sapEmpty.getConfig().getApplyTo()).isEmpty(); selector = - ApplyTo.templateRoles( - ApplyTo.TemplateRole.USER, - ApplyTo.TemplateRole.SYSTEM, - ApplyTo.TemplateRole.ASSISTANT, - ApplyTo.TemplateRole.DEVELOPER, - ApplyTo.TemplateRole.TOOL) - .sourceLanguage("de-DE"); + ApplyTo.templateRoles(USER, SYSTEM, ASSISTANT, DEVELOPER, TOOL).sourceLanguage("de-DE"); assertThat(selector.getCategory().getValue()).isEqualTo("template_roles"); assertThat(selector.getItems()) From 2d3ef5b48f5b46aa874937980782fd579f581c54 Mon Sep 17 00:00:00 2001 From: SAP Cloud SDK Bot Date: Wed, 25 Feb 2026 12:54:23 +0000 Subject: [PATCH 13/32] Formatting --- .../src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java index 10a55e0eb..67fe72b8f 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java @@ -4,8 +4,6 @@ import static com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector.CategoryEnum.TEMPLATE_ROLES; import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector; -import java.util.Collection; -import java.util.List; import java.util.Objects; import java.util.stream.Stream; import javax.annotation.Nonnull; From e6ebe2f3317f5317240b7044d04097aa6083efb0 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Wed, 25 Feb 2026 14:02:06 +0100 Subject: [PATCH 14/32] updating constructors --- .../main/java/com/sap/ai/sdk/orchestration/ApplyTo.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java index 10a55e0eb..65f30c87b 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java @@ -10,6 +10,7 @@ import java.util.stream.Stream; import javax.annotation.Nonnull; import lombok.Getter; +import lombok.RequiredArgsConstructor; /** * Convenience builder for {@link SAPDocumentTranslationApplyToSelector}. @@ -17,13 +18,12 @@ *

This avoids passing raw strings for template roles and keeps sample-code readable. */ public final class ApplyTo { - private ApplyTo() {} - /** * Supported values for {@code items[]} when {@code category=template_roles}. * *

These map to the roles used in prompt templates. */ + @RequiredArgsConstructor public enum TemplateRole { /** Template role for user messages. */ USER("user"), @@ -41,10 +41,6 @@ public enum TemplateRole { TOOL("tool"); @Getter private final String value; - - TemplateRole(@Nonnull final String value) { - this.value = value; - } } /** From aec7e6ef8595eb8290666d943f0de8e3d306acef Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Mon, 2 Mar 2026 11:13:13 +0100 Subject: [PATCH 15/32] fix tests + mistake from old pr --- docs/release_notes.md | 2 +- orchestration/pom.xml | 3 +- .../com/sap/ai/sdk/orchestration/ApplyTo.java | 71 -------------- .../sdk/orchestration/TranslationConfig.java | 92 ++++++++++++++++++- .../OrchestrationModuleConfigTest.java | 89 +++++++++--------- .../app/services/OrchestrationService.java | 6 +- 6 files changed, 133 insertions(+), 130 deletions(-) delete mode 100644 orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java diff --git a/docs/release_notes.md b/docs/release_notes.md index ec2146464..57392305e 100644 --- a/docs/release_notes.md +++ b/docs/release_notes.md @@ -26,7 +26,7 @@ ### 📈 Improvements -- [Orchestration] Added new API `TranslationConfig#withApplyTo` to support partial translation for user's input. +- [Orchestration] Added new API `TranslationConfig#withApplyTo` to support partial translation for a user's input. ### 🐛 Fixed Issues diff --git a/orchestration/pom.xml b/orchestration/pom.xml index 5dd469371..f569f732b 100644 --- a/orchestration/pom.xml +++ b/orchestration/pom.xml @@ -8,7 +8,8 @@ orchestration Orchestration client - SAP Cloud SDK for AI is the official Software Development Kit (SDK) for SAP AI Core, SAP Generative AI Hub, and Orchestration Service. This is the client for the Orchestration Service. + SAP Cloud SDK for AI is the official Software Development Kit (SDK) for SAP AI Core, SAP Generative AI + Hub, and Orchestration Service. This is the client for the Orchestration Service. https://github.com/SAP/ai-sdk-java?tab=readme-ov-file#documentation diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java deleted file mode 100644 index 15554ce35..000000000 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/ApplyTo.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.sap.ai.sdk.orchestration; - -import static com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector.CategoryEnum.PLACEHOLDERS; -import static com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector.CategoryEnum.TEMPLATE_ROLES; - -import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector; -import java.util.Objects; -import java.util.stream.Stream; -import javax.annotation.Nonnull; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -/** - * Convenience builder for {@link SAPDocumentTranslationApplyToSelector}. - * - *

This avoids passing raw strings for template roles and keeps sample-code readable. - */ -public final class ApplyTo { - /** - * Supported values for {@code items[]} when {@code category=template_roles}. - * - *

These map to the roles used in prompt templates. - */ - @RequiredArgsConstructor - public enum TemplateRole { - /** Template role for user messages. */ - USER("user"), - - /** Template role for system messages. */ - SYSTEM("system"), - - /** Template role for assistant messages. */ - ASSISTANT("assistant"), - - /** Template role for developer messages. */ - DEVELOPER("developer"), - - /** Template role for tool messages. */ - TOOL("tool"); - - @Getter private final String value; - } - - /** - * Start an {@code apply_to} selector for placeholder names in {@code placeholder_values}. - * - * @param names The placeholder keys to translate. - * @return A selector with {@code category=placeholders} and the given items. - */ - @Nonnull - public static SAPDocumentTranslationApplyToSelector placeholders(@Nonnull final String... names) { - return SAPDocumentTranslationApplyToSelector.create().category(PLACEHOLDERS).items(names); - } - - /** - * Start an {@code apply_to} selector for prompt template message roles. - * - * @param roles The template roles to translate. - * @return A selector with {@code category=template_roles} and the given items. - */ - @Nonnull - public static SAPDocumentTranslationApplyToSelector templateRoles( - @Nonnull final TemplateRole... roles) { - final var roleStrings = - Stream.of(roles).filter(Objects::nonNull).map(TemplateRole::getValue).toList(); - - return SAPDocumentTranslationApplyToSelector.create() - .category(TEMPLATE_ROLES) - .items(roleStrings); - } -} diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index f830bd895..b58304485 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -1,5 +1,8 @@ package com.sap.ai.sdk.orchestration; +import static com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector.CategoryEnum.PLACEHOLDERS; +import static com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector.CategoryEnum.TEMPLATE_ROLES; + import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationApplyToSelector; import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationInput; import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationInputConfig; @@ -7,8 +10,11 @@ import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutputConfig; import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutputTargetLanguage; import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; import javax.annotation.Nonnull; import lombok.AccessLevel; +import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Value; import lombok.With; @@ -23,13 +29,38 @@ * @since 1.14.0 */ public interface TranslationConfig { + /** + * Supported values for {@code items[]} when {@code category=template_roles}. + * + *

These map to the roles used in prompt templates. + */ + @RequiredArgsConstructor + enum TemplateRole { + /** Template role for user messages. */ + USER("user"), + + /** Template role for system messages. */ + SYSTEM("system"), + + /** Template role for assistant messages. */ + ASSISTANT("assistant"), + + /** Template role for developer messages. */ + DEVELOPER("developer"), + + /** Template role for tool messages. */ + TOOL("tool"); + + @Getter private final String value; + } + /** Input configuration for translation. */ @Value @RequiredArgsConstructor(access = AccessLevel.PRIVATE) class Input implements TranslationConfig { String targetLanguage; - @With String sourceLanguage; + @Getter @With String sourceLanguage; /** * Optional selection(s) to translate. If empty or null, translation is applied to the whole @@ -40,7 +71,7 @@ class Input implements TranslationConfig { @Nonnull SAPDocumentTranslationInput createSAPDocumentTranslationInput() { val translationType = SAPDocumentTranslationInput.TypeEnum.SAP_DOCUMENT_TRANSLATION; - final var conf = SAPDocumentTranslationInputConfig.create().targetLanguage(targetLanguage); + final var conf = SAPDocumentTranslationInputConfig.create().targetLanguage(targetLanguage).sourceLanguage(sourceLanguage); if (applyTo != null && !applyTo.isEmpty()) { conf.applyTo(applyTo); @@ -48,6 +79,59 @@ SAPDocumentTranslationInput createSAPDocumentTranslationInput() { return SAPDocumentTranslationInput.create().type(translationType).config(conf); } + + /** + * Start an {@code apply_to} selector for placeholder names in {@code placeholder_values}. + * + * @param names The placeholder keys to translate. + * @return A selector with {@code category=placeholders} and the given items. + */ + @Nonnull + public Input applyToPlaceholders(@Nonnull final String... names) { + if (names.length == 0) { + return this; + } + final var selector = + SAPDocumentTranslationApplyToSelector.create().category(PLACEHOLDERS).items(names); + return addApplyToSelector(selector); + } + + /** + * Start an {@code apply_to} selector for prompt template message roles. + * + * @param roles The template roles to translate. + * @return A selector with {@code category=template_roles} and the given items. + */ + @Nonnull + public Input applyToTemplateRoles(@Nonnull final TranslationConfig.TemplateRole... roles) { + final var roleStrings = + Stream.of(roles) + .filter(Objects::nonNull) + .map(TranslationConfig.TemplateRole::getValue) + .toList(); + + if (roleStrings.isEmpty()) { + return this; + } + + final var selector = + SAPDocumentTranslationApplyToSelector.create() + .category(TEMPLATE_ROLES) + .items(roleStrings); + return addApplyToSelector(selector); + } + + private Input addApplyToSelector( + @Nonnull final SAPDocumentTranslationApplyToSelector selector) { + Objects.requireNonNull(selector, "selector must not be null"); + final var appended = new java.util.ArrayList(); + if (applyTo != null && !applyTo.isEmpty()) { + appended.addAll(applyTo); + } + appended.add(selector); + + return withApplyTo(List.copyOf(appended)); + } } /** Output configuration for translation. */ @@ -56,7 +140,7 @@ SAPDocumentTranslationInput createSAPDocumentTranslationInput() { class Output implements TranslationConfig { String targetLanguage; - @With String sourceLanguage; + @Getter @With String sourceLanguage; @Nonnull SAPDocumentTranslationOutput createSAPDocumentTranslationOutput() { @@ -97,4 +181,4 @@ static TranslationConfig.Input translateInputTo(@Nonnull final String targetLang static TranslationConfig.Output translateOutputTo(@Nonnull final String targetLanguage) { return new TranslationConfig.Output(targetLanguage, null); } -} +} \ No newline at end of file diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java index 639e288e5..d5bbc172c 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java @@ -1,13 +1,10 @@ package com.sap.ai.sdk.orchestration; -import static com.sap.ai.sdk.orchestration.ApplyTo.TemplateRole.ASSISTANT; -import static com.sap.ai.sdk.orchestration.ApplyTo.TemplateRole.DEVELOPER; -import static com.sap.ai.sdk.orchestration.ApplyTo.TemplateRole.SYSTEM; -import static com.sap.ai.sdk.orchestration.ApplyTo.TemplateRole.TOOL; -import static com.sap.ai.sdk.orchestration.ApplyTo.TemplateRole.USER; import static com.sap.ai.sdk.orchestration.AzureFilterThreshold.ALLOW_SAFE_LOW_MEDIUM; import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.GPT_4O; import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.Parameter.MAX_TOKENS; +import static com.sap.ai.sdk.orchestration.TranslationConfig.TemplateRole.ASSISTANT; +import static com.sap.ai.sdk.orchestration.TranslationConfig.TemplateRole.USER; import static com.sap.ai.sdk.orchestration.model.DataRepositoryType.VECTOR; import static com.sap.ai.sdk.orchestration.model.GroundingModuleConfig.TypeEnum.DOCUMENT_GROUNDING_SERVICE; import static org.assertj.core.api.Assertions.assertThat; @@ -28,6 +25,7 @@ import com.sap.ai.sdk.orchestration.model.Template; import com.sap.ai.sdk.orchestration.model.TemplateRef; import com.sap.ai.sdk.orchestration.model.TemplateRefByID; +import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutputTargetLanguage; import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -150,45 +148,31 @@ void testTranslationConfig() { TranslationConfig.translateInputTo("en-US").withSourceLanguage("de-DE"); var outputTranslationConfig = TranslationConfig.translateOutputTo("de-DE").withSourceLanguage("en-US"); - var config = - new OrchestrationModuleConfig() - .withLlmConfig(GPT_4O) - .withInputTranslationConfig(inputTranslationConfig) - .withOutputTranslationConfig(outputTranslationConfig); - - assertThat(config.getInputTranslationConfig()).isNotNull(); - assertThat(config.getInputTranslationConfig().getConfig().getTargetLanguage()) - .isEqualTo("en-US"); - assertThat(config.getInputTranslationConfig().getConfig().getSourceLanguage()) - .isEqualTo( - inputTranslationConfig - .createSAPDocumentTranslationInput() - .getConfig() - .getSourceLanguage()); - assertThat(config.getOutputTranslationConfig()).isNotNull(); - assertThat(config.getOutputTranslationConfig().getConfig().getTargetLanguage()) - .isEqualTo( - outputTranslationConfig - .createSAPDocumentTranslationOutput() - .getConfig() - .getTargetLanguage()); - assertThat(config.getOutputTranslationConfig().getConfig().getSourceLanguage()) - .isEqualTo( - outputTranslationConfig - .createSAPDocumentTranslationOutput() - .getConfig() - .getSourceLanguage()); + var sapInput = inputTranslationConfig.createSAPDocumentTranslationInput(); + var sapOutput = outputTranslationConfig.createSAPDocumentTranslationOutput(); + + assertThat(sapInput.getConfig()).isNotNull(); + assertThat(sapInput.getConfig().getTargetLanguage()).isEqualTo("en-US"); + assertThat(sapInput.getConfig().getSourceLanguage()) + .isEqualTo(inputTranslationConfig.getSourceLanguage()); + + assertThat(sapOutput.getConfig()).isNotNull(); + assertThat( + ((SAPDocumentTranslationOutputTargetLanguage.InnerString) + sapOutput.getConfig().getTargetLanguage()) + .value()) + .isEqualTo("de-DE"); + assertThat(sapOutput.getConfig().getSourceLanguage()) + .isEqualTo(outputTranslationConfig.getSourceLanguage()); } @Test void testTranslationConfigApplyToSelectors() { - var selector = ApplyTo.placeholders("exam_type", "topic").sourceLanguage("de-DE"); - - final var inputTranslationConfig = - TranslationConfig.translateInputTo("en-US").withApplyTo(List.of(selector)); + var inputTranslationConfig = + TranslationConfig.translateInputTo("en-US").applyToPlaceholders("exam_type", "topic"); - final var sapInput = inputTranslationConfig.createSAPDocumentTranslationInput(); + var sapInput = inputTranslationConfig.createSAPDocumentTranslationInput(); assertThat(sapInput.getConfig().getTargetLanguage()).isEqualTo("en-US"); assertThat(sapInput.getConfig().getApplyTo()).hasSize(1); assertThat(sapInput.getConfig().getApplyTo().get(0).getCategory().getValue()) @@ -196,22 +180,31 @@ void testTranslationConfigApplyToSelectors() { assertThat(sapInput.getConfig().getApplyTo().get(0).getItems()) .containsExactly("exam_type", "topic"); + // applyTo == empty list + final var inputEmpty = TranslationConfig.translateInputTo("en-US").applyToPlaceholders().applyToTemplateRoles(); + final var sapEmpty = inputEmpty.createSAPDocumentTranslationInput(); + assertThat(sapEmpty.getConfig().getApplyTo()).isEmpty(); + + // applyTo == null list final var inputNull = TranslationConfig.translateInputTo("en-US"); final var sapNull = inputNull.createSAPDocumentTranslationInput(); assertThat(sapNull.getConfig().getApplyTo()).isEmpty(); - // applyTo == empty list - final var inputEmpty = TranslationConfig.translateInputTo("en-US").withApplyTo(List.of()); - final var sapEmpty = inputEmpty.createSAPDocumentTranslationInput(); - assertThat(sapEmpty.getConfig().getApplyTo()).isEmpty(); + inputTranslationConfig = + TranslationConfig.translateInputTo("en-US").applyToTemplateRoles(USER, ASSISTANT); - selector = - ApplyTo.templateRoles(USER, SYSTEM, ASSISTANT, DEVELOPER, TOOL).sourceLanguage("de-DE"); + sapInput = inputTranslationConfig.createSAPDocumentTranslationInput(); + assertThat(sapInput.getConfig().getTargetLanguage()).isEqualTo("en-US"); + assertThat(sapInput.getConfig().getApplyTo()).hasSize(1); + assertThat(sapInput.getConfig().getApplyTo().get(0).getCategory().getValue()) + .isEqualTo("template_roles"); + assertThat(sapInput.getConfig().getApplyTo().get(0).getItems()) + .containsExactly("user", "assistant"); - assertThat(selector.getCategory().getValue()).isEqualTo("template_roles"); - assertThat(selector.getItems()) - .containsExactly("user", "system", "assistant", "developer", "tool"); - assertThat(selector.getSourceLanguage()).isEqualTo("de-DE"); + // applyTo != null but empty list (should be treated like unset) + final var inputExplicitEmptyList = TranslationConfig.translateInputTo("en-US").withApplyTo(List.of()); + final var sapExplicitEmptyList = inputExplicitEmptyList.createSAPDocumentTranslationInput(); + assertThat(sapExplicitEmptyList.getConfig().getApplyTo()).isEmpty(); } @Test 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 fdbe3c326..fa22e8cdf 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 @@ -9,7 +9,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.sap.ai.sdk.core.AiCoreService; -import com.sap.ai.sdk.orchestration.ApplyTo; import com.sap.ai.sdk.orchestration.AzureContentFilter; import com.sap.ai.sdk.orchestration.AzureFilterThreshold; import com.sap.ai.sdk.orchestration.DpiMasking; @@ -709,10 +708,7 @@ public OrchestrationChatResponse translation() { .withTemplateConfig(templatingConfig) .withInputTranslationConfig( TranslationConfig.translateInputTo("en-US") - .withApplyTo( - List.of( - // Translate only selected placeholder values from German to English - ApplyTo.placeholders("exam_type", "topic"))) + .applyToPlaceholders("exam_type", "topic") .withSourceLanguage("de-DE")) .withOutputTranslationConfig( TranslationConfig.translateOutputTo("de-DE").withSourceLanguage("en-US")); From 593d4c4ee0c02ef8c6a8bda0fc72e2c5b47fea4c Mon Sep 17 00:00:00 2001 From: SAP Cloud SDK Bot Date: Mon, 2 Mar 2026 10:14:56 +0000 Subject: [PATCH 16/32] Formatting --- .../com/sap/ai/sdk/orchestration/TranslationConfig.java | 7 +++++-- .../sdk/orchestration/OrchestrationModuleConfigTest.java | 8 +++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index b58304485..6d1ec833a 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -71,7 +71,10 @@ class Input implements TranslationConfig { @Nonnull SAPDocumentTranslationInput createSAPDocumentTranslationInput() { val translationType = SAPDocumentTranslationInput.TypeEnum.SAP_DOCUMENT_TRANSLATION; - final var conf = SAPDocumentTranslationInputConfig.create().targetLanguage(targetLanguage).sourceLanguage(sourceLanguage); + final var conf = + SAPDocumentTranslationInputConfig.create() + .targetLanguage(targetLanguage) + .sourceLanguage(sourceLanguage); if (applyTo != null && !applyTo.isEmpty()) { conf.applyTo(applyTo); @@ -181,4 +184,4 @@ static TranslationConfig.Input translateInputTo(@Nonnull final String targetLang static TranslationConfig.Output translateOutputTo(@Nonnull final String targetLanguage) { return new TranslationConfig.Output(targetLanguage, null); } -} \ No newline at end of file +} diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java index d5bbc172c..6be778d49 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java @@ -22,10 +22,10 @@ import com.sap.ai.sdk.orchestration.model.MaskingModuleConfigProviders; import com.sap.ai.sdk.orchestration.model.ResponseFormatJsonObject; import com.sap.ai.sdk.orchestration.model.ResponseFormatJsonSchema; +import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutputTargetLanguage; import com.sap.ai.sdk.orchestration.model.Template; import com.sap.ai.sdk.orchestration.model.TemplateRef; import com.sap.ai.sdk.orchestration.model.TemplateRefByID; -import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutputTargetLanguage; import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -181,7 +181,8 @@ void testTranslationConfigApplyToSelectors() { .containsExactly("exam_type", "topic"); // applyTo == empty list - final var inputEmpty = TranslationConfig.translateInputTo("en-US").applyToPlaceholders().applyToTemplateRoles(); + final var inputEmpty = + TranslationConfig.translateInputTo("en-US").applyToPlaceholders().applyToTemplateRoles(); final var sapEmpty = inputEmpty.createSAPDocumentTranslationInput(); assertThat(sapEmpty.getConfig().getApplyTo()).isEmpty(); @@ -202,7 +203,8 @@ void testTranslationConfigApplyToSelectors() { .containsExactly("user", "assistant"); // applyTo != null but empty list (should be treated like unset) - final var inputExplicitEmptyList = TranslationConfig.translateInputTo("en-US").withApplyTo(List.of()); + final var inputExplicitEmptyList = + TranslationConfig.translateInputTo("en-US").withApplyTo(List.of()); final var sapExplicitEmptyList = inputExplicitEmptyList.createSAPDocumentTranslationInput(); assertThat(sapExplicitEmptyList.getConfig().getApplyTo()).isEmpty(); } From 4b13d42c51f1547c4c35ba9f7df4d58fe79cc442 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Mon, 2 Mar 2026 11:56:32 +0100 Subject: [PATCH 17/32] formatting --- .../com/sap/ai/sdk/orchestration/TranslationConfig.java | 7 +++++-- .../sdk/orchestration/OrchestrationModuleConfigTest.java | 8 +++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index b58304485..6d1ec833a 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -71,7 +71,10 @@ class Input implements TranslationConfig { @Nonnull SAPDocumentTranslationInput createSAPDocumentTranslationInput() { val translationType = SAPDocumentTranslationInput.TypeEnum.SAP_DOCUMENT_TRANSLATION; - final var conf = SAPDocumentTranslationInputConfig.create().targetLanguage(targetLanguage).sourceLanguage(sourceLanguage); + final var conf = + SAPDocumentTranslationInputConfig.create() + .targetLanguage(targetLanguage) + .sourceLanguage(sourceLanguage); if (applyTo != null && !applyTo.isEmpty()) { conf.applyTo(applyTo); @@ -181,4 +184,4 @@ static TranslationConfig.Input translateInputTo(@Nonnull final String targetLang static TranslationConfig.Output translateOutputTo(@Nonnull final String targetLanguage) { return new TranslationConfig.Output(targetLanguage, null); } -} \ No newline at end of file +} diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java index d5bbc172c..6be778d49 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java @@ -22,10 +22,10 @@ import com.sap.ai.sdk.orchestration.model.MaskingModuleConfigProviders; import com.sap.ai.sdk.orchestration.model.ResponseFormatJsonObject; import com.sap.ai.sdk.orchestration.model.ResponseFormatJsonSchema; +import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutputTargetLanguage; import com.sap.ai.sdk.orchestration.model.Template; import com.sap.ai.sdk.orchestration.model.TemplateRef; import com.sap.ai.sdk.orchestration.model.TemplateRefByID; -import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutputTargetLanguage; import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; @@ -181,7 +181,8 @@ void testTranslationConfigApplyToSelectors() { .containsExactly("exam_type", "topic"); // applyTo == empty list - final var inputEmpty = TranslationConfig.translateInputTo("en-US").applyToPlaceholders().applyToTemplateRoles(); + final var inputEmpty = + TranslationConfig.translateInputTo("en-US").applyToPlaceholders().applyToTemplateRoles(); final var sapEmpty = inputEmpty.createSAPDocumentTranslationInput(); assertThat(sapEmpty.getConfig().getApplyTo()).isEmpty(); @@ -202,7 +203,8 @@ void testTranslationConfigApplyToSelectors() { .containsExactly("user", "assistant"); // applyTo != null but empty list (should be treated like unset) - final var inputExplicitEmptyList = TranslationConfig.translateInputTo("en-US").withApplyTo(List.of()); + final var inputExplicitEmptyList = + TranslationConfig.translateInputTo("en-US").withApplyTo(List.of()); final var sapExplicitEmptyList = inputExplicitEmptyList.createSAPDocumentTranslationInput(); assertThat(sapExplicitEmptyList.getConfig().getApplyTo()).isEmpty(); } From 3ce80b18b78182e0c5f7a7f87d444b9219835ca4 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Mon, 2 Mar 2026 12:14:11 +0100 Subject: [PATCH 18/32] fix source language --- .../com/sap/ai/sdk/orchestration/TranslationConfig.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index 6d1ec833a..7dafcb3c3 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -71,13 +71,12 @@ class Input implements TranslationConfig { @Nonnull SAPDocumentTranslationInput createSAPDocumentTranslationInput() { val translationType = SAPDocumentTranslationInput.TypeEnum.SAP_DOCUMENT_TRANSLATION; - final var conf = - SAPDocumentTranslationInputConfig.create() - .targetLanguage(targetLanguage) - .sourceLanguage(sourceLanguage); + final var conf = SAPDocumentTranslationInputConfig.create().targetLanguage(targetLanguage); if (applyTo != null && !applyTo.isEmpty()) { conf.applyTo(applyTo); + } else { + conf.sourceLanguage(sourceLanguage); } return SAPDocumentTranslationInput.create().type(translationType).config(conf); From b7f03e62985e6633b9ae961d33ac7b49c293627b Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Mon, 2 Mar 2026 12:44:06 +0100 Subject: [PATCH 19/32] fix tests --- .../sdk/orchestration/TranslationConfig.java | 1 - .../OrchestrationModuleConfigTest.java | 48 +++++++++++++------ 2 files changed, 34 insertions(+), 15 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index 7dafcb3c3..244c382de 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -125,7 +125,6 @@ public Input applyToTemplateRoles(@Nonnull final TranslationConfig.TemplateRole. private Input addApplyToSelector( @Nonnull final SAPDocumentTranslationApplyToSelector selector) { - Objects.requireNonNull(selector, "selector must not be null"); final var appended = new java.util.ArrayList(); if (applyTo != null && !applyTo.isEmpty()) { appended.addAll(applyTo); diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java index 6be778d49..42b08c2ea 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java @@ -170,15 +170,21 @@ void testTranslationConfig() { @Test void testTranslationConfigApplyToSelectors() { var inputTranslationConfig = - TranslationConfig.translateInputTo("en-US").applyToPlaceholders("exam_type", "topic"); + TranslationConfig.translateInputTo("en-US") + .applyToPlaceholders("exam_type", "topic") + .applyToTemplateRoles(USER, ASSISTANT); var sapInput = inputTranslationConfig.createSAPDocumentTranslationInput(); assertThat(sapInput.getConfig().getTargetLanguage()).isEqualTo("en-US"); - assertThat(sapInput.getConfig().getApplyTo()).hasSize(1); + assertThat(sapInput.getConfig().getApplyTo()).hasSize(2); assertThat(sapInput.getConfig().getApplyTo().get(0).getCategory().getValue()) .isEqualTo("placeholders"); assertThat(sapInput.getConfig().getApplyTo().get(0).getItems()) .containsExactly("exam_type", "topic"); + assertThat(sapInput.getConfig().getApplyTo().get(1).getCategory().getValue()) + .isEqualTo("template_roles"); + assertThat(sapInput.getConfig().getApplyTo().get(1).getItems()) + .containsExactly("user", "assistant"); // applyTo == empty list final var inputEmpty = @@ -191,24 +197,38 @@ void testTranslationConfigApplyToSelectors() { final var sapNull = inputNull.createSAPDocumentTranslationInput(); assertThat(sapNull.getConfig().getApplyTo()).isEmpty(); - inputTranslationConfig = - TranslationConfig.translateInputTo("en-US").applyToTemplateRoles(USER, ASSISTANT); - - sapInput = inputTranslationConfig.createSAPDocumentTranslationInput(); - assertThat(sapInput.getConfig().getTargetLanguage()).isEqualTo("en-US"); - assertThat(sapInput.getConfig().getApplyTo()).hasSize(1); - assertThat(sapInput.getConfig().getApplyTo().get(0).getCategory().getValue()) - .isEqualTo("template_roles"); - assertThat(sapInput.getConfig().getApplyTo().get(0).getItems()) - .containsExactly("user", "assistant"); - - // applyTo != null but empty list (should be treated like unset) + // applyTo != null but empty list final var inputExplicitEmptyList = TranslationConfig.translateInputTo("en-US").withApplyTo(List.of()); final var sapExplicitEmptyList = inputExplicitEmptyList.createSAPDocumentTranslationInput(); assertThat(sapExplicitEmptyList.getConfig().getApplyTo()).isEmpty(); } + @Test + void testTranslationConfigViaModuleConfig() { + final var inputTranslation = + TranslationConfig.translateInputTo("en-US").withSourceLanguage("de-DE"); + final var outputTranslation = + TranslationConfig.translateOutputTo("de-DE").withSourceLanguage("en-US"); + + final var config = + new OrchestrationModuleConfig() + .withLlmConfig(GPT_4O) + .withInputTranslationConfig(inputTranslation) + .withOutputTranslationConfig(outputTranslation); + + assertThat(config.getInputTranslationConfig()).isNotNull(); + assertThat(config.getInputTranslationConfig().getConfig().getTargetLanguage()) + .isEqualTo("en-US"); + + assertThat(config.getOutputTranslationConfig()).isNotNull(); + assertThat( + ((SAPDocumentTranslationOutputTargetLanguage.InnerString) + config.getOutputTranslationConfig().getConfig().getTargetLanguage()) + .value()) + .isEqualTo("de-DE"); + } + @Test void testParams() { // test withParams(Map) From 7186853fb4c51c340b74e6b1219b34a1a986d059 Mon Sep 17 00:00:00 2001 From: SAP Cloud SDK Bot Date: Mon, 2 Mar 2026 11:50:29 +0000 Subject: [PATCH 20/32] Formatting --- .../java/com/sap/ai/sdk/orchestration/TranslationConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index 481210df2..244c382de 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -182,4 +182,4 @@ static TranslationConfig.Input translateInputTo(@Nonnull final String targetLang static TranslationConfig.Output translateOutputTo(@Nonnull final String targetLanguage) { return new TranslationConfig.Output(targetLanguage, null); } -} \ No newline at end of file +} From 7011d6db69718ef37b02041dbd088f1d2db3d4e4 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Mon, 2 Mar 2026 12:53:01 +0100 Subject: [PATCH 21/32] chore: retrigger CI From c4d0dff9bc2e286d6cc806c6eaf4e35eb2d70523 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Mon, 2 Mar 2026 17:25:45 +0100 Subject: [PATCH 22/32] some updates --- .../com/sap/ai/sdk/orchestration/TranslationConfig.java | 7 ++++--- .../sdk/orchestration/OrchestrationModuleConfigTest.java | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index 244c382de..424d9ea97 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -9,6 +9,7 @@ import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutput; import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutputConfig; import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutputTargetLanguage; +import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.stream.Stream; @@ -64,7 +65,7 @@ class Input implements TranslationConfig { /** * Optional selection(s) to translate. If empty or null, translation is applied to the whole - * user input. + * message. */ @With List applyTo; @@ -125,13 +126,13 @@ public Input applyToTemplateRoles(@Nonnull final TranslationConfig.TemplateRole. private Input addApplyToSelector( @Nonnull final SAPDocumentTranslationApplyToSelector selector) { - final var appended = new java.util.ArrayList(); + final var appended = new ArrayList(); if (applyTo != null && !applyTo.isEmpty()) { appended.addAll(applyTo); } appended.add(selector); - return withApplyTo(List.copyOf(appended)); + return withApplyTo(appended); } } diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java index 42b08c2ea..abc04a492 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java @@ -220,6 +220,8 @@ void testTranslationConfigViaModuleConfig() { assertThat(config.getInputTranslationConfig()).isNotNull(); assertThat(config.getInputTranslationConfig().getConfig().getTargetLanguage()) .isEqualTo("en-US"); + assertThat(config.getInputTranslationConfig().getConfig().getSourceLanguage()) + .isEqualTo("de-DE"); assertThat(config.getOutputTranslationConfig()).isNotNull(); assertThat( @@ -227,6 +229,8 @@ void testTranslationConfigViaModuleConfig() { config.getOutputTranslationConfig().getConfig().getTargetLanguage()) .value()) .isEqualTo("de-DE"); + assertThat(config.getOutputTranslationConfig().getConfig().getSourceLanguage()) + .isEqualTo("en-US"); } @Test From f73443fbfe6fefcdfc0212ffa7a5fddd62270c5c Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Tue, 3 Mar 2026 10:55:42 +0100 Subject: [PATCH 23/32] allowing apply_to to be null --- .../sap/ai/sdk/orchestration/TranslationConfig.java | 12 +++++++----- .../orchestration/OrchestrationModuleConfigTest.java | 10 ++-------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index 424d9ea97..06204dfe2 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -14,6 +14,7 @@ import java.util.Objects; import java.util.stream.Stream; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; @@ -67,16 +68,17 @@ class Input implements TranslationConfig { * Optional selection(s) to translate. If empty or null, translation is applied to the whole * message. */ - @With List applyTo; + @With @Nullable List applyTo; @Nonnull SAPDocumentTranslationInput createSAPDocumentTranslationInput() { val translationType = SAPDocumentTranslationInput.TypeEnum.SAP_DOCUMENT_TRANSLATION; - final var conf = SAPDocumentTranslationInputConfig.create().targetLanguage(targetLanguage); + final var conf = + SAPDocumentTranslationInputConfig.create() + .targetLanguage(targetLanguage) + .applyTo(applyTo); - if (applyTo != null && !applyTo.isEmpty()) { - conf.applyTo(applyTo); - } else { + if (applyTo == null || applyTo.isEmpty()) { conf.sourceLanguage(sourceLanguage); } diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java index abc04a492..c07ae9090 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java @@ -190,18 +190,12 @@ void testTranslationConfigApplyToSelectors() { final var inputEmpty = TranslationConfig.translateInputTo("en-US").applyToPlaceholders().applyToTemplateRoles(); final var sapEmpty = inputEmpty.createSAPDocumentTranslationInput(); - assertThat(sapEmpty.getConfig().getApplyTo()).isEmpty(); + assertThat(sapEmpty.getConfig().getApplyTo()).isNull(); // applyTo == null list final var inputNull = TranslationConfig.translateInputTo("en-US"); final var sapNull = inputNull.createSAPDocumentTranslationInput(); - assertThat(sapNull.getConfig().getApplyTo()).isEmpty(); - - // applyTo != null but empty list - final var inputExplicitEmptyList = - TranslationConfig.translateInputTo("en-US").withApplyTo(List.of()); - final var sapExplicitEmptyList = inputExplicitEmptyList.createSAPDocumentTranslationInput(); - assertThat(sapExplicitEmptyList.getConfig().getApplyTo()).isEmpty(); + assertThat(sapNull.getConfig().getApplyTo()).isNull(); } @Test From fece5601e4bb42b4c3033cd4662d80ba500a955a Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Tue, 3 Mar 2026 11:07:57 +0100 Subject: [PATCH 24/32] release notes update --- docs/release_notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release_notes.md b/docs/release_notes.md index 7717caf76..9181ad711 100644 --- a/docs/release_notes.md +++ b/docs/release_notes.md @@ -16,7 +16,7 @@ ### 📈 Improvements -- [Orchestration] Added new API `TranslationConfig#withApplyTo` to support partial translation for a user's input. +- [Orchestration] Added new API `TranslationConfig#applyToPlaceholders` and `TranslationConfig#applyToTemplateRoles` to support partial translation for a message. ### 🐛 Fixed Issues From f8914971fdb7c039296c55d5af7d56d4448c249a Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Tue, 3 Mar 2026 11:36:39 +0100 Subject: [PATCH 25/32] making withApplyTo private --- .../com/sap/ai/sdk/orchestration/TranslationConfig.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index 06204dfe2..921fb0c24 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -68,7 +68,7 @@ class Input implements TranslationConfig { * Optional selection(s) to translate. If empty or null, translation is applied to the whole * message. */ - @With @Nullable List applyTo; + @Nullable List applyTo; @Nonnull SAPDocumentTranslationInput createSAPDocumentTranslationInput() { @@ -126,6 +126,10 @@ public Input applyToTemplateRoles(@Nonnull final TranslationConfig.TemplateRole. return addApplyToSelector(selector); } + private Input withApplyTo(@Nullable final List applyTo) { + return new TranslationConfig.Input(targetLanguage, sourceLanguage, applyTo); + } + private Input addApplyToSelector( @Nonnull final SAPDocumentTranslationApplyToSelector selector) { final var appended = new ArrayList(); From f68184517161324873b4625d9cceece6f2ec2daa Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Tue, 3 Mar 2026 13:59:28 +0100 Subject: [PATCH 26/32] reverting pom formatting --- orchestration/pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/orchestration/pom.xml b/orchestration/pom.xml index f569f732b..5dd469371 100644 --- a/orchestration/pom.xml +++ b/orchestration/pom.xml @@ -8,8 +8,7 @@ orchestration Orchestration client - SAP Cloud SDK for AI is the official Software Development Kit (SDK) for SAP AI Core, SAP Generative AI - Hub, and Orchestration Service. This is the client for the Orchestration Service. + SAP Cloud SDK for AI is the official Software Development Kit (SDK) for SAP AI Core, SAP Generative AI Hub, and Orchestration Service. This is the client for the Orchestration Service. https://github.com/SAP/ai-sdk-java?tab=readme-ov-file#documentation From 4083c44bea170d049c2e925f16b2d0e6e8a2c6ab Mon Sep 17 00:00:00 2001 From: Nourhan Islam Shata <163640161+n-o-u-r-h-a-n@users.noreply.github.com> Date: Tue, 3 Mar 2026 14:17:06 +0100 Subject: [PATCH 27/32] Update orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java Co-authored-by: Jonas-Isr --- .../java/com/sap/ai/sdk/orchestration/TranslationConfig.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index 921fb0c24..d666d8f8c 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -92,10 +92,7 @@ SAPDocumentTranslationInput createSAPDocumentTranslationInput() { * @return A selector with {@code category=placeholders} and the given items. */ @Nonnull - public Input applyToPlaceholders(@Nonnull final String... names) { - if (names.length == 0) { - return this; - } + public Input applyToPlaceholders(@Nonnull final String name, @Nonnull final String... additionalNames) { final var selector = SAPDocumentTranslationApplyToSelector.create().category(PLACEHOLDERS).items(names); return addApplyToSelector(selector); From 8edc04fd8adede31d1465129b3cf187e1d245afa Mon Sep 17 00:00:00 2001 From: SAP Cloud SDK Bot Date: Tue, 3 Mar 2026 13:17:54 +0000 Subject: [PATCH 28/32] Formatting --- .../java/com/sap/ai/sdk/orchestration/TranslationConfig.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index d666d8f8c..5a6b4036b 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -92,7 +92,8 @@ SAPDocumentTranslationInput createSAPDocumentTranslationInput() { * @return A selector with {@code category=placeholders} and the given items. */ @Nonnull - public Input applyToPlaceholders(@Nonnull final String name, @Nonnull final String... additionalNames) { + public Input applyToPlaceholders( + @Nonnull final String name, @Nonnull final String... additionalNames) { final var selector = SAPDocumentTranslationApplyToSelector.create().category(PLACEHOLDERS).items(names); return addApplyToSelector(selector); From de9d424d30d9396488b037b2426e300a0364a41d Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Tue, 3 Mar 2026 15:52:30 +0100 Subject: [PATCH 29/32] fixing source language issue --- .../sdk/orchestration/TranslationConfig.java | 48 ++++++++++++------- .../OrchestrationModuleConfigTest.java | 18 +++---- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index 5a6b4036b..a33d0f914 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -11,7 +11,6 @@ import com.sap.ai.sdk.orchestration.model.SAPDocumentTranslationOutputTargetLanguage; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.stream.Stream; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -62,11 +61,11 @@ enum TemplateRole { class Input implements TranslationConfig { String targetLanguage; - @Getter @With String sourceLanguage; + @Getter String sourceLanguage; /** * Optional selection(s) to translate. If empty or null, translation is applied to the whole - * message. + * message. If used, source language will be applied per selector. */ @Nullable List applyTo; @@ -88,33 +87,37 @@ SAPDocumentTranslationInput createSAPDocumentTranslationInput() { /** * Start an {@code apply_to} selector for placeholder names in {@code placeholder_values}. * - * @param names The placeholder keys to translate. + * @param name The first placeholder name to translate. + * @param additionalNames Additional placeholder names to translate. * @return A selector with {@code category=placeholders} and the given items. */ @Nonnull public Input applyToPlaceholders( @Nonnull final String name, @Nonnull final String... additionalNames) { final var selector = - SAPDocumentTranslationApplyToSelector.create().category(PLACEHOLDERS).items(names); + SAPDocumentTranslationApplyToSelector.create() + .category(PLACEHOLDERS) + .items(Stream.concat(Stream.of(name), Stream.of(additionalNames)).toList()); return addApplyToSelector(selector); } /** * Start an {@code apply_to} selector for prompt template message roles. * + * @param role The first template role to translate. * @param roles The template roles to translate. * @return A selector with {@code category=template_roles} and the given items. */ @Nonnull - public Input applyToTemplateRoles(@Nonnull final TranslationConfig.TemplateRole... roles) { - final var roleStrings = - Stream.of(roles) - .filter(Objects::nonNull) - .map(TranslationConfig.TemplateRole::getValue) - .toList(); - - if (roleStrings.isEmpty()) { - return this; + public Input applyToTemplateRoles( + @Nonnull final TranslationConfig.TemplateRole role, + @Nonnull final TranslationConfig.TemplateRole... roles) { + final var roleStrings = new ArrayList(1 + roles.length); + roleStrings.add(role.getValue()); + for (final var r : roles) { + if (r != null) { + roleStrings.add(r.getValue()); + } } final var selector = @@ -124,8 +127,19 @@ public Input applyToTemplateRoles(@Nonnull final TranslationConfig.TemplateRole. return addApplyToSelector(selector); } - private Input withApplyTo(@Nullable final List applyTo) { - return new TranslationConfig.Input(targetLanguage, sourceLanguage, applyTo); + /** + * Set the source language for this translation. If no selectors are used, this applies to the + * whole message. If selectors are used, this applies to the most recently added selector. + * + * @param sourceLanguage The source language code + * @return A new Input with the given source language applied. + */ + @Nonnull + public Input withSourceLanguage(@Nonnull final String sourceLanguage) { + if (applyTo != null) { + applyTo.get(applyTo.size() - 1).sourceLanguage(sourceLanguage); + } + return new Input(targetLanguage, sourceLanguage, applyTo); } private Input addApplyToSelector( @@ -136,7 +150,7 @@ private Input addApplyToSelector( } appended.add(selector); - return withApplyTo(appended); + return new TranslationConfig.Input(targetLanguage, sourceLanguage, appended); } } diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java index c07ae9090..9cde42daa 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationModuleConfigTest.java @@ -172,10 +172,16 @@ void testTranslationConfigApplyToSelectors() { var inputTranslationConfig = TranslationConfig.translateInputTo("en-US") .applyToPlaceholders("exam_type", "topic") - .applyToTemplateRoles(USER, ASSISTANT); + .withSourceLanguage("de-DE") + .applyToTemplateRoles(USER, ASSISTANT) + .withSourceLanguage("en-US"); var sapInput = inputTranslationConfig.createSAPDocumentTranslationInput(); assertThat(sapInput.getConfig().getTargetLanguage()).isEqualTo("en-US"); + assertThat(sapInput.getConfig().getSourceLanguage()).isNull(); + assertThat(sapInput.getConfig().getApplyTo().get(0).getSourceLanguage()).isEqualTo("de-DE"); + assertThat(sapInput.getConfig().getApplyTo().get(1).getSourceLanguage()).isEqualTo("en-US"); + assertThat(sapInput.getConfig().getApplyTo()).hasSize(2); assertThat(sapInput.getConfig().getApplyTo().get(0).getCategory().getValue()) .isEqualTo("placeholders"); @@ -186,15 +192,11 @@ void testTranslationConfigApplyToSelectors() { assertThat(sapInput.getConfig().getApplyTo().get(1).getItems()) .containsExactly("user", "assistant"); - // applyTo == empty list - final var inputEmpty = - TranslationConfig.translateInputTo("en-US").applyToPlaceholders().applyToTemplateRoles(); - final var sapEmpty = inputEmpty.createSAPDocumentTranslationInput(); - assertThat(sapEmpty.getConfig().getApplyTo()).isNull(); - // applyTo == null list - final var inputNull = TranslationConfig.translateInputTo("en-US"); + final var inputNull = TranslationConfig.translateInputTo("en-US").withSourceLanguage("de-DE"); final var sapNull = inputNull.createSAPDocumentTranslationInput(); + assertThat(sapNull.getConfig().getTargetLanguage()).isEqualTo("en-US"); + assertThat(sapNull.getConfig().getSourceLanguage()).isEqualTo("de-DE"); assertThat(sapNull.getConfig().getApplyTo()).isNull(); } From 08968964ee28986c503fead2843708f0835fb87a Mon Sep 17 00:00:00 2001 From: Nourhan Islam Shata <163640161+n-o-u-r-h-a-n@users.noreply.github.com> Date: Thu, 5 Mar 2026 11:22:32 +0200 Subject: [PATCH 30/32] Update orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java Co-authored-by: Jonas-Isr --- .../java/com/sap/ai/sdk/orchestration/TranslationConfig.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index a33d0f914..24d207ecb 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -128,7 +128,9 @@ public Input applyToTemplateRoles( } /** - * Set the source language for this translation. If no selectors are used, this applies to the + * Set the source language for this translation. + *
+ * Important Note: If no selectors are used, this applies to the * whole message. If selectors are used, this applies to the most recently added selector. * * @param sourceLanguage The source language code From e6181e6a3838f3fd87668452c42e4a4cdb536d78 Mon Sep 17 00:00:00 2001 From: SAP Cloud SDK Bot Date: Thu, 5 Mar 2026 09:23:23 +0000 Subject: [PATCH 31/32] Formatting --- .../com/sap/ai/sdk/orchestration/TranslationConfig.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index 24d207ecb..5960bb323 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -128,10 +128,9 @@ public Input applyToTemplateRoles( } /** - * Set the source language for this translation. - *
- * Important Note: If no selectors are used, this applies to the - * whole message. If selectors are used, this applies to the most recently added selector. + * Set the source language for this translation.
+ * Important Note: If no selectors are used, this applies to the whole message. + * If selectors are used, this applies to the most recently added selector. * * @param sourceLanguage The source language code * @return A new Input with the given source language applied. From 1c7bda660f9d880cf6bfc84dee14c9d0d26328d3 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Thu, 5 Mar 2026 11:23:54 +0200 Subject: [PATCH 32/32] removing getter due to value presence --- .../java/com/sap/ai/sdk/orchestration/TranslationConfig.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java index a33d0f914..110bd8849 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TranslationConfig.java @@ -61,7 +61,7 @@ enum TemplateRole { class Input implements TranslationConfig { String targetLanguage; - @Getter String sourceLanguage; + String sourceLanguage; /** * Optional selection(s) to translate. If empty or null, translation is applied to the whole @@ -160,7 +160,7 @@ private Input addApplyToSelector( class Output implements TranslationConfig { String targetLanguage; - @Getter @With String sourceLanguage; + @With String sourceLanguage; @Nonnull SAPDocumentTranslationOutput createSAPDocumentTranslationOutput() {