From 7f9397b5d0bcacade16dd9b143c3f6e8680ec26e Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Fri, 28 Nov 2025 15:13:28 +0100 Subject: [PATCH 01/15] Updating TemplateConfig.java. --- .../ai/sdk/orchestration/TemplateConfig.java | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java index 15bab9c85..e030751a5 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java @@ -42,7 +42,34 @@ public static OrchestrationTemplate create() { @Nonnull public static ReferenceBuilder reference() { final var templ = TemplateRefByScenarioNameVersion.create(); - return s -> n -> v -> new OrchestrationTemplateReference(templ.scenario(s).name(n).version(v)); + return s -> + n -> + v -> + new OrchestrationTemplateReference( + templ + .scenario(s) + .name(n) + .version(v) + .scope(TemplateRefByScenarioNameVersion.ScopeEnum.TENANT)); + } + + /** + * Build a template reference with resource group scope. + * + * @return An intermediate object to build the template reference. + */ + @Nonnull + public static ReferenceBuilder referenceWithResourceGroupScope() { + final var templ = TemplateRefByScenarioNameVersion.create(); + return s -> + n -> + v -> + new OrchestrationTemplateReference( + templ + .scenario(s) + .name(n) + .version(v) + .scope(TemplateRefByScenarioNameVersion.ScopeEnum.RESOURCE_GROUP)); } /** Intermediate object to build a template reference. */ @@ -56,7 +83,20 @@ public interface ReferenceBuilder { */ @Nonnull default OrchestrationTemplateReference byId(@Nonnull final String id) { - return new OrchestrationTemplateReference(TemplateRefByID.create().id(id)); + return new OrchestrationTemplateReference( + TemplateRefByID.create().id(id).scope(TemplateRefByID.ScopeEnum.TENANT)); + } + + /** + * Build a template reference with the given id and resource group scope. + * + * @param id The id of the template. + * @return A template reference with the given id. + */ + @Nonnull + default OrchestrationTemplateReference byIdWithResourceGroupScope(@Nonnull final String id) { + return new OrchestrationTemplateReference( + TemplateRefByID.create().id(id).scope(TemplateRefByID.ScopeEnum.RESOURCE_GROUP)); } /** From 3a84ad76ed957d4bbf9a7bed109732495a39be6c Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Thu, 15 Jan 2026 17:25:04 +0100 Subject: [PATCH 02/15] rolling back --- .../ai/sdk/orchestration/TemplateConfig.java | 44 +------------------ 1 file changed, 2 insertions(+), 42 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java index e030751a5..15bab9c85 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java @@ -42,34 +42,7 @@ public static OrchestrationTemplate create() { @Nonnull public static ReferenceBuilder reference() { final var templ = TemplateRefByScenarioNameVersion.create(); - return s -> - n -> - v -> - new OrchestrationTemplateReference( - templ - .scenario(s) - .name(n) - .version(v) - .scope(TemplateRefByScenarioNameVersion.ScopeEnum.TENANT)); - } - - /** - * Build a template reference with resource group scope. - * - * @return An intermediate object to build the template reference. - */ - @Nonnull - public static ReferenceBuilder referenceWithResourceGroupScope() { - final var templ = TemplateRefByScenarioNameVersion.create(); - return s -> - n -> - v -> - new OrchestrationTemplateReference( - templ - .scenario(s) - .name(n) - .version(v) - .scope(TemplateRefByScenarioNameVersion.ScopeEnum.RESOURCE_GROUP)); + return s -> n -> v -> new OrchestrationTemplateReference(templ.scenario(s).name(n).version(v)); } /** Intermediate object to build a template reference. */ @@ -83,20 +56,7 @@ public interface ReferenceBuilder { */ @Nonnull default OrchestrationTemplateReference byId(@Nonnull final String id) { - return new OrchestrationTemplateReference( - TemplateRefByID.create().id(id).scope(TemplateRefByID.ScopeEnum.TENANT)); - } - - /** - * Build a template reference with the given id and resource group scope. - * - * @param id The id of the template. - * @return A template reference with the given id. - */ - @Nonnull - default OrchestrationTemplateReference byIdWithResourceGroupScope(@Nonnull final String id) { - return new OrchestrationTemplateReference( - TemplateRefByID.create().id(id).scope(TemplateRefByID.ScopeEnum.RESOURCE_GROUP)); + return new OrchestrationTemplateReference(TemplateRefByID.create().id(id)); } /** From 49be7aa6006b78811923294ad493934fac800228 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Wed, 21 Jan 2026 13:18:47 +0100 Subject: [PATCH 03/15] Orchestration Convenience RG-Scoped Prompt Templates --- .../ai/sdk/orchestration/TemplateConfig.java | 50 ++++++++++-- .../OrchestrationConvenienceUnitTest.java | 39 ++++++++- .../orchestration/OrchestrationUnitTest.java | 76 +++++++++++++++++- ...emplateReferenceResourceGroupResponse.json | 79 +++++++++++++++++++ ...lateReferenceResourceGroupByIdRequest.json | 26 ++++++ ...ferenceResourceGroupByScenarioRequest.json | 28 +++++++ .../controllers/OrchestrationController.java | 38 +++++++-- .../app/services/OrchestrationService.java | 70 +++++++++++++++- .../src/main/resources/static/index.html | 42 ++++++++-- .../app/controllers/OrchestrationTest.java | 33 +++++++- 10 files changed, 448 insertions(+), 33 deletions(-) create mode 100644 orchestration/src/test/resources/__files/templateReferenceResourceGroupResponse.json create mode 100644 orchestration/src/test/resources/templateReferenceResourceGroupByIdRequest.json create mode 100644 orchestration/src/test/resources/templateReferenceResourceGroupByScenarioRequest.json diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java index 15bab9c85..65bcc6afc 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java @@ -35,28 +35,64 @@ public static OrchestrationTemplate create() { } /** - * Build a template reference. + * Build a template reference with tenant level scope. * * @return An intermediate object to build the template reference. */ @Nonnull - public static ReferenceBuilder reference() { + public static ReferenceBuilder referenceTenant() { final var templ = TemplateRefByScenarioNameVersion.create(); - return s -> n -> v -> new OrchestrationTemplateReference(templ.scenario(s).name(n).version(v)); + final var scope = TemplateRefByScenarioNameVersion.ScopeEnum.TENANT; + + return s -> + n -> + v -> + new OrchestrationTemplateReference( + templ.scenario(s).name(n).version(v).scope(scope)); + } + + /** + * Build a template reference with resource group scope. + * + * @return An intermediate object to build the template reference. + */ + @Nonnull + public static ReferenceBuilder referenceResourceGroup() { + final var templ = TemplateRefByScenarioNameVersion.create(); + final var scope = TemplateRefByScenarioNameVersion.ScopeEnum.RESOURCE_GROUP; + + return s -> + n -> + v -> + new OrchestrationTemplateReference( + templ.scenario(s).name(n).version(v).scope(scope)); } - /** Intermediate object to build a template reference. */ + /** Intermediate object to build a template referenceTenant. */ @FunctionalInterface public interface ReferenceBuilder { /** - * Build a template reference with the given id. + * Build a template reference with the given id for tenant scope. + * + * @param id The id of the template. + * @return A template reference with the given id. + */ + @Nonnull + default OrchestrationTemplateReference byIdTenant(@Nonnull final String id) { + final var scope = TemplateRefByID.ScopeEnum.TENANT; + return new OrchestrationTemplateReference(TemplateRefByID.create().id(id).scope(scope)); + } + + /** + * Build a template reference with the given id for resource group scope. * * @param id The id of the template. * @return A template reference with the given id. */ @Nonnull - default OrchestrationTemplateReference byId(@Nonnull final String id) { - return new OrchestrationTemplateReference(TemplateRefByID.create().id(id)); + default OrchestrationTemplateReference byIdResourceGroup(@Nonnull final String id) { + final var scope = TemplateRefByID.ScopeEnum.RESOURCE_GROUP; + return new OrchestrationTemplateReference(TemplateRefByID.create().id(id).scope(scope)); } /** diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java index 6ac9a7e83..fd11bb9b3 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java @@ -158,7 +158,7 @@ void testTemplateConstruction() { @Test void testTemplateReferenceConstruction() { - var templateReferenceId = TemplateConfig.reference().byId("id"); + var templateReferenceId = TemplateConfig.referenceTenant().byIdTenant("id"); var expectedTemplateReferenceId = new OrchestrationTemplateReference(TemplateRefByID.create().id("id")); var templateReferenceIdLowLevel = @@ -166,8 +166,17 @@ void testTemplateReferenceConstruction() { assertThat(templateReferenceId).isEqualTo(expectedTemplateReferenceId); assertThat(templateReferenceId.toLowLevel()).isEqualTo(templateReferenceIdLowLevel); + templateReferenceId = TemplateConfig.referenceResourceGroup().byIdResourceGroup("id"); + var scope = TemplateRefByID.ScopeEnum.RESOURCE_GROUP; + expectedTemplateReferenceId = + new OrchestrationTemplateReference(TemplateRefByID.create().id("id").scope(scope)); + templateReferenceIdLowLevel = + TemplateRef.create().templateRef(TemplateRefByID.create().id("id").scope(scope)); + assertThat(templateReferenceId).isEqualTo(expectedTemplateReferenceId); + assertThat(templateReferenceId.toLowLevel()).isEqualTo(templateReferenceIdLowLevel); + var templateReferenceScenarioNameVersion = - TemplateConfig.reference().byScenario("scenario").name("name").version("version"); + TemplateConfig.referenceTenant().byScenario("scenario").name("name").version("version"); var expectedTemplateReferenceScenarioNameVersion = new OrchestrationTemplateReference( TemplateRefByScenarioNameVersion.create() @@ -185,6 +194,32 @@ void testTemplateReferenceConstruction() { .isEqualTo(expectedTemplateReferenceScenarioNameVersion); assertThat(templateReferenceScenarioNameVersion.toLowLevel()) .isEqualTo(templateReferenceScenarioNameVersionLowLevel); + + templateReferenceScenarioNameVersion = + TemplateConfig.referenceResourceGroup() + .byScenario("scenario") + .name("name") + .version("version"); + var scopeScenario = TemplateRefByScenarioNameVersion.ScopeEnum.RESOURCE_GROUP; + expectedTemplateReferenceScenarioNameVersion = + new OrchestrationTemplateReference( + TemplateRefByScenarioNameVersion.create() + .scenario("scenario") + .name("name") + .version("version") + .scope(scopeScenario)); + templateReferenceScenarioNameVersionLowLevel = + TemplateRef.create() + .templateRef( + TemplateRefByScenarioNameVersion.create() + .scenario("scenario") + .name("name") + .version("version") + .scope(scopeScenario)); + assertThat(templateReferenceScenarioNameVersion) + .isEqualTo(expectedTemplateReferenceScenarioNameVersion); + assertThat(templateReferenceScenarioNameVersion.toLowLevel()) + .isEqualTo(templateReferenceScenarioNameVersionLowLevel); } @Test diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java index 6bfd757af..6484e03f0 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java @@ -1259,7 +1259,7 @@ void testResponseFormatText() throws IOException { } @Test - void testTemplateFromPromptRegistryById() throws IOException { + void testTemplateFromPromptRegistryByIdTenant() throws IOException { { stubFor( post(anyUrl()) @@ -1268,7 +1268,8 @@ void testTemplateFromPromptRegistryById() throws IOException { .withBodyFile("templateReferenceResponse.json") .withHeader("Content-Type", "application/json"))); - var template = TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16"); + var template = + TemplateConfig.referenceTenant().byIdTenant("21cb1358-0bf1-4f43-870b-00f14d0f9f16"); var configWithTemplate = config.withTemplateConfig(template); var inputParams = Map.of("language", "Italian", "input", "Cloud ERP systems"); @@ -1285,7 +1286,40 @@ void testTemplateFromPromptRegistryById() throws IOException { } @Test - void testTemplateFromPromptRegistryByScenario() throws IOException { + void testTemplateFromPromptRegistryByIdResourceGroup() throws IOException { + { + stubFor( + post(anyUrl()) + .willReturn( + aResponse() + .withBodyFile("templateReferenceResourceGroupResponse.json") + .withHeader("Content-Type", "application/json"))); + + var template = + TemplateConfig.referenceResourceGroup() + .byIdResourceGroup("2cd4aea1-dffb-4d5d-b96d-96e29b595025"); + var configWithTemplate = config.withLlmConfig(GPT_4O_MINI).withTemplateConfig(template); + + var inputParams = + Map.of( + "categories", + "Finance, Tech, Sports", + "inputExample", + "What's the latest news on the stock market?"); + var prompt = new OrchestrationPrompt(inputParams); + + final var response = client.chatCompletion(prompt, configWithTemplate); + assertThat(response.getContent()).startsWith("Finance"); + assertThat(response.getOriginalResponse().getIntermediateResults().getTemplating()) + .hasSize(2); + + final String request = fileLoaderStr.apply("templateReferenceResourceGroupByIdRequest.json"); + verify(postRequestedFor(anyUrl()).withRequestBody(equalToJson(request))); + } + } + + @Test + void testTemplateFromPromptRegistryByScenarioTenant() throws IOException { stubFor( post(anyUrl()) .willReturn( @@ -1293,7 +1327,8 @@ void testTemplateFromPromptRegistryByScenario() throws IOException { .withBodyFile("templateReferenceResponse.json") .withHeader("Content-Type", "application/json"))); - var template = TemplateConfig.reference().byScenario("test").name("test").version("0.0.1"); + var template = + TemplateConfig.referenceTenant().byScenario("test").name("test").version("0.0.1"); var configWithTemplate = config.withTemplateConfig(template); var inputParams = Map.of("language", "Italian", "input", "Cloud ERP systems"); @@ -1307,6 +1342,39 @@ void testTemplateFromPromptRegistryByScenario() throws IOException { verify(postRequestedFor(anyUrl()).withRequestBody(equalToJson(request))); } + @Test + void testTemplateFromPromptRegistryByScenarioResourceGroup() throws IOException { + stubFor( + post(anyUrl()) + .willReturn( + aResponse() + .withBodyFile("templateReferenceResourceGroupResponse.json") + .withHeader("Content-Type", "application/json"))); + + var template = + TemplateConfig.referenceResourceGroup() + .byScenario("categorization") + .name("example-prompt-template") + .version("0.0.1"); + var configWithTemplate = config.withLlmConfig(GPT_4O_MINI).withTemplateConfig(template); + + var inputParams = + Map.of( + "categories", + "Finance, Tech, Sports", + "inputExample", + "What's the latest news on the stock market?"); + var prompt = new OrchestrationPrompt(inputParams); + + final var response = client.chatCompletion(prompt, configWithTemplate); + assertThat(response.getContent()).startsWith("Finance"); + assertThat(response.getOriginalResponse().getIntermediateResults().getTemplating()).hasSize(2); + + final String request = + fileLoaderStr.apply("templateReferenceResourceGroupByScenarioRequest.json"); + verify(postRequestedFor(anyUrl()).withRequestBody(equalToJson(request))); + } + @Test void testTemplateFromInput() throws IOException { stubFor( diff --git a/orchestration/src/test/resources/__files/templateReferenceResourceGroupResponse.json b/orchestration/src/test/resources/__files/templateReferenceResourceGroupResponse.json new file mode 100644 index 000000000..34017f89a --- /dev/null +++ b/orchestration/src/test/resources/__files/templateReferenceResourceGroupResponse.json @@ -0,0 +1,79 @@ +{ + "request_id": "176cbc1e-7451-9b78-bb3e-278abd576a66", + "intermediate_results": { + "templating": [ + { + "role": "system", + "content": "You classify input text into the two following categories: Finance, Tech, Sports" + }, + { + "content": "What's the latest news on the stock market?", + "role": "user" + } + ], + "llm": { + "id": "chatcmpl-D09WL0JIzGaEF1RwbaTKitAspDKhO", + "object": "chat.completion", + "created": 1768928969, + "model": "gpt-4o-mini-2024-07-18", + "system_fingerprint": "fp_f97eff32c5", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "Finance" + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 2, + "prompt_tokens": 35, + "total_tokens": 37, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 0, + "rejected_prediction_tokens": 0 + } + } + } + }, + "final_result": { + "id": "chatcmpl-D09WL0JIzGaEF1RwbaTKitAspDKhO", + "object": "chat.completion", + "created": 1768928969, + "model": "gpt-4o-mini-2024-07-18", + "system_fingerprint": "fp_f97eff32c5", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "Finance" + }, + "finish_reason": "stop" + } + ], + "usage": { + "completion_tokens": 2, + "prompt_tokens": 35, + "total_tokens": 37, + "prompt_tokens_details": { + "audio_tokens": 0, + "cached_tokens": 0 + }, + "completion_tokens_details": { + "accepted_prediction_tokens": 0, + "audio_tokens": 0, + "reasoning_tokens": 0, + "rejected_prediction_tokens": 0 + } + } + } +} diff --git a/orchestration/src/test/resources/templateReferenceResourceGroupByIdRequest.json b/orchestration/src/test/resources/templateReferenceResourceGroupByIdRequest.json new file mode 100644 index 000000000..0dad3f949 --- /dev/null +++ b/orchestration/src/test/resources/templateReferenceResourceGroupByIdRequest.json @@ -0,0 +1,26 @@ +{ + "config": { + "modules": { + "prompt_templating": { + "prompt": { + "template_ref": { + "id": "2cd4aea1-dffb-4d5d-b96d-96e29b595025", + "scope": "resource_group" + } + }, + "model": { + "name": "gpt-4o-mini", + "version": "latest", + "params": {}, + "timeout": 600, + "max_retries": 2 + } + } + } + }, + "placeholder_values": { + "categories": "Finance, Tech, Sports", + "inputExample": "What's the latest news on the stock market?" + }, + "messages_history": [] +} diff --git a/orchestration/src/test/resources/templateReferenceResourceGroupByScenarioRequest.json b/orchestration/src/test/resources/templateReferenceResourceGroupByScenarioRequest.json new file mode 100644 index 000000000..867f4a13c --- /dev/null +++ b/orchestration/src/test/resources/templateReferenceResourceGroupByScenarioRequest.json @@ -0,0 +1,28 @@ +{ + "config": { + "modules": { + "prompt_templating": { + "prompt": { + "template_ref": { + "scenario": "categorization", + "name": "example-prompt-template", + "version": "0.0.1", + "scope": "resource_group" + } + }, + "model": { + "name": "gpt-4o-mini", + "version": "latest", + "params": {}, + "timeout": 600, + "max_retries": 2 + } + } + } + }, + "placeholder_values": { + "categories": "Finance, Tech, Sports", + "inputExample": "What's the latest news on the stock market?" + }, + "messages_history": [] +} diff --git a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OrchestrationController.java b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OrchestrationController.java index f9ad72596..8b2f1e9ea 100644 --- a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OrchestrationController.java +++ b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OrchestrationController.java @@ -307,22 +307,48 @@ Object responseFormatJsonObject( return response.getContent(); } - @GetMapping("/templateFromPromptRegistryById") + @GetMapping("/templateFromPromptRegistryByIdTenant") @Nonnull - Object templateFromPromptRegistryById( + Object templateFromPromptRegistryByIdTenant( @RequestParam(value = "format", required = false) final String format) { - final var response = service.templateFromPromptRegistryById("cloud ERP systems"); + final var response = service.templateFromPromptRegistryByIdTenant("cloud ERP systems"); if ("json".equals(format)) { return response; } return response.getContent(); } - @GetMapping("/templateFromPromptRegistryByScenario") + @GetMapping("/templateFromPromptRegistryByIdResourceGroup") @Nonnull - Object templateFromPromptRegistryByScenario( + Object templateFromPromptRegistryByIdResourceGroup( @RequestParam(value = "format", required = false) final String format) { - final var response = service.templateFromPromptRegistryByScenario("cloud ERP systems"); + final var response = + service.templateFromPromptRegistryByIdResourceGroup( + "What's the latest news on the stock market?"); + if ("json".equals(format)) { + return response; + } + return response.getContent(); + } + + @GetMapping("/templateFromPromptRegistryByScenarioTenant") + @Nonnull + Object templateFromPromptRegistryByScenarioTenant( + @RequestParam(value = "format", required = false) final String format) { + final var response = service.templateFromPromptRegistryByScenarioTenant("cloud ERP systems"); + if ("json".equals(format)) { + return response; + } + return response.getContent(); + } + + @GetMapping("/templateFromPromptRegistryByScenarioResourceGroup") + @Nonnull + Object templateFromPromptRegistryByScenarioResourceGroup( + @RequestParam(value = "format", required = false) final String format) { + final var response = + service.templateFromPromptRegistryByScenarioResourceGroup( + "What's the latest news on the stock market?"); if ("json".equals(format)) { return response; } 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 e8456da09..8ae645b37 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 @@ -543,11 +543,13 @@ public OrchestrationChatResponse responseFormatText(@Nonnull final String word) * @return the assistant response object */ @Nonnull - public OrchestrationChatResponse templateFromPromptRegistryById(@Nonnull final String topic) { + public OrchestrationChatResponse templateFromPromptRegistryByIdTenant( + @Nonnull final String topic) { final var llmWithImageSupportConfig = new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); - val template = TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16"); + val template = + TemplateConfig.referenceTenant().byIdTenant("21cb1358-0bf1-4f43-870b-00f14d0f9f16"); val configWithTemplate = llmWithImageSupportConfig.withTemplateConfig(template); val inputParams = Map.of("language", "Italian", "input", topic); @@ -556,6 +558,36 @@ public OrchestrationChatResponse templateFromPromptRegistryById(@Nonnull final S return client.chatCompletion(prompt, configWithTemplate); } + /** + * Chat request to OpenAI through the Orchestration service using a template from the prompt + * registry. + * + * @link SAP + * AI Core: Orchestration - Templating + * @param inputExample the example to send to the assistant + * @return the assistant response object + */ + @Nonnull + public OrchestrationChatResponse templateFromPromptRegistryByIdResourceGroup( + @Nonnull final String inputExample) { + final var llmWithImageSupportConfig = + new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); + + final var destination = + new AiCoreService().getInferenceDestination("i749902").forScenario("orchestration"); + final var clientWithResourceGroup = new OrchestrationClient(destination); + + val template = + TemplateConfig.referenceResourceGroup() + .byIdResourceGroup("2cd4aea1-dffb-4d5d-b96d-96e29b595025"); + val configWithTemplate = llmWithImageSupportConfig.withTemplateConfig(template); + + val inputParams = Map.of("categories", "Finance, Tech, Sports", "inputExample", inputExample); + val prompt = new OrchestrationPrompt(inputParams); + + return clientWithResourceGroup.chatCompletion(prompt, configWithTemplate); + } + /** * Chat request to OpenAI through the Orchestration service using a template from the prompt * registry. @@ -566,9 +598,10 @@ public OrchestrationChatResponse templateFromPromptRegistryById(@Nonnull final S * @return the assistant response object */ @Nonnull - public OrchestrationChatResponse templateFromPromptRegistryByScenario( + public OrchestrationChatResponse templateFromPromptRegistryByScenarioTenant( @Nonnull final String topic) { - val template = TemplateConfig.reference().byScenario("test").name("test").version("0.0.1"); + val template = + TemplateConfig.referenceTenant().byScenario("test").name("test").version("0.0.1"); val configWithTemplate = config.withTemplateConfig(template); val inputParams = Map.of("language", "Italian", "input", topic); @@ -577,6 +610,35 @@ public OrchestrationChatResponse templateFromPromptRegistryByScenario( return client.chatCompletion(prompt, configWithTemplate); } + /** + * Chat request to OpenAI through the Orchestration service using a template from the prompt + * registry. + * + * @link SAP + * AI Core: Orchestration - Templating + * @param inputExample the example to send to the assistant + * @return the assistant response object + */ + @Nonnull + public OrchestrationChatResponse templateFromPromptRegistryByScenarioResourceGroup( + @Nonnull final String inputExample) { + final var destination = + new AiCoreService().getInferenceDestination("i749902").forScenario("orchestration"); + final var clientWithResourceGroup = new OrchestrationClient(destination); + + val template = + TemplateConfig.referenceResourceGroup() + .byScenario("categorization") + .name("example-prompt-template") + .version("0.0.1"); + val configWithTemplate = config.withTemplateConfig(template); + + val inputParams = Map.of("categories", "Finance, Tech, Sports", "inputExample", inputExample); + val prompt = new OrchestrationPrompt(inputParams); + + return clientWithResourceGroup.chatCompletion(prompt, configWithTemplate); + } + /** * Chat request to an LLM through the Orchestration service using a local template file. * diff --git a/sample-code/spring-app/src/main/resources/static/index.html b/sample-code/spring-app/src/main/resources/static/index.html index 5393c1804..7f32b01b8 100644 --- a/sample-code/spring-app/src/main/resources/static/index.html +++ b/sample-code/spring-app/src/main/resources/static/index.html @@ -509,12 +509,12 @@

Orchestration

  • - Chat request to an LLM through the Orchestration service + Chat request to an LLM through the Orchestration service in tenant scope using a template from the prompt registry identified by ID.
    @@ -523,12 +523,42 @@

    Orchestration

  • - Chat request to an LLM through the Orchestration service + Chat request to an LLM through the Orchestration service in resource group + scope + using a template from the prompt registry identified by + ID. +
    +
    +
  • +
  • +
    + +
    + Chat request to an LLM through the Orchestration service in tenant scope + using a template from the prompt registry identified by + Scenario, name, and version. +
    +
    +
  • +
  • +
    + +
    + Chat request to an LLM through the Orchestration service in resource group + scope using a template from the prompt registry identified by Scenario, name, and version.
    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 6c805ff60..b7029e924 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 @@ -401,16 +401,41 @@ void testResponseFormatText() { } @Test - void testTemplateFromPromptRegistryById() { - val result = service.templateFromPromptRegistryById("Cloud ERP systems").getOriginalResponse(); + void testTemplateFromPromptRegistryByIdTenant() { + val result = + service.templateFromPromptRegistryByIdTenant("Cloud ERP systems").getOriginalResponse(); + val choices = (result.getFinalResult()).getChoices(); + assertThat(choices.get(0).getMessage().getContent()).isNotEmpty(); + } + + @Test + void testTemplateFromPromptRegistryByIdResourceGroup() { + val result = + service + .templateFromPromptRegistryByIdResourceGroup( + "What's the latest news on the stock market?") + .getOriginalResponse(); val choices = (result.getFinalResult()).getChoices(); assertThat(choices.get(0).getMessage().getContent()).isNotEmpty(); } @Test - void testTemplateFromPromptRegistryByScenario() { + void testTemplateFromPromptRegistryByScenarioTenant() { val result = - service.templateFromPromptRegistryByScenario("Cloud ERP systems").getOriginalResponse(); + service + .templateFromPromptRegistryByScenarioTenant("Cloud ERP systems") + .getOriginalResponse(); + val choices = (result.getFinalResult()).getChoices(); + assertThat(choices.get(0).getMessage().getContent()).isNotEmpty(); + } + + @Test + void testTemplateFromPromptRegistryByScenarioResourceGroup() { + val result = + service + .templateFromPromptRegistryByScenarioResourceGroup( + "What's the latest news on the stock market?") + .getOriginalResponse(); val choices = (result.getFinalResult()).getChoices(); assertThat(choices.get(0).getMessage().getContent()).isNotEmpty(); } From cb1ac3871c23af3509a28712e243cf0d26458dce Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Wed, 21 Jan 2026 14:42:13 +0100 Subject: [PATCH 04/15] Triggering --- .../java/com/sap/ai/sdk/app/services/OrchestrationService.java | 1 + 1 file changed, 1 insertion(+) 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 e8cc455e8..b941c3a77 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 @@ -536,6 +536,7 @@ public OrchestrationChatResponse responseFormatText(@Nonnull final String word) Template.create() .template(List.of(template.createChatMessage())) .responseFormat(ResponseFormatText.create().type(ResponseFormatText.TypeEnum.TEXT)); + val configWithTemplate = config.withTemplateConfig(templatingConfig); val prompt = From c288e4d523e760c60c84c93d0b8619bb187e5112 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Wed, 21 Jan 2026 14:42:56 +0100 Subject: [PATCH 05/15] Triggering 2 --- .../java/com/sap/ai/sdk/app/services/OrchestrationService.java | 1 - 1 file changed, 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 b941c3a77..e8cc455e8 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 @@ -536,7 +536,6 @@ public OrchestrationChatResponse responseFormatText(@Nonnull final String word) Template.create() .template(List.of(template.createChatMessage())) .responseFormat(ResponseFormatText.create().type(ResponseFormatText.TypeEnum.TEXT)); - val configWithTemplate = config.withTemplateConfig(templatingConfig); val prompt = From 536a9175e46fd5bf9e62dc8c026401b700c1637b Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Wed, 21 Jan 2026 16:44:01 +0100 Subject: [PATCH 06/15] Rolling back renaming avoiding API breakage. --- .../java/com/sap/ai/sdk/orchestration/TemplateConfig.java | 6 +++--- .../sdk/orchestration/OrchestrationConvenienceUnitTest.java | 4 ++-- .../com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java | 4 ++-- .../com/sap/ai/sdk/app/services/OrchestrationService.java | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java index 65bcc6afc..2436d0702 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java @@ -40,7 +40,7 @@ public static OrchestrationTemplate create() { * @return An intermediate object to build the template reference. */ @Nonnull - public static ReferenceBuilder referenceTenant() { + public static ReferenceBuilder reference() { final var templ = TemplateRefByScenarioNameVersion.create(); final var scope = TemplateRefByScenarioNameVersion.ScopeEnum.TENANT; @@ -68,7 +68,7 @@ public static ReferenceBuilder referenceResourceGroup() { templ.scenario(s).name(n).version(v).scope(scope)); } - /** Intermediate object to build a template referenceTenant. */ + /** Intermediate object to build a template reference. */ @FunctionalInterface public interface ReferenceBuilder { /** @@ -78,7 +78,7 @@ public interface ReferenceBuilder { * @return A template reference with the given id. */ @Nonnull - default OrchestrationTemplateReference byIdTenant(@Nonnull final String id) { + default OrchestrationTemplateReference byId(@Nonnull final String id) { final var scope = TemplateRefByID.ScopeEnum.TENANT; return new OrchestrationTemplateReference(TemplateRefByID.create().id(id).scope(scope)); } diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java index fd11bb9b3..0fc35350f 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java @@ -158,7 +158,7 @@ void testTemplateConstruction() { @Test void testTemplateReferenceConstruction() { - var templateReferenceId = TemplateConfig.referenceTenant().byIdTenant("id"); + var templateReferenceId = TemplateConfig.reference().byId("id"); var expectedTemplateReferenceId = new OrchestrationTemplateReference(TemplateRefByID.create().id("id")); var templateReferenceIdLowLevel = @@ -176,7 +176,7 @@ void testTemplateReferenceConstruction() { assertThat(templateReferenceId.toLowLevel()).isEqualTo(templateReferenceIdLowLevel); var templateReferenceScenarioNameVersion = - TemplateConfig.referenceTenant().byScenario("scenario").name("name").version("version"); + TemplateConfig.reference().byScenario("scenario").name("name").version("version"); var expectedTemplateReferenceScenarioNameVersion = new OrchestrationTemplateReference( TemplateRefByScenarioNameVersion.create() diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java index 0f52a8888..2ffa5e1ee 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java @@ -1269,7 +1269,7 @@ void testTemplateFromPromptRegistryByIdTenant() throws IOException { .withHeader("Content-Type", "application/json"))); var template = - TemplateConfig.referenceTenant().byIdTenant("21cb1358-0bf1-4f43-870b-00f14d0f9f16"); + TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16"); var configWithTemplate = config.withTemplateConfig(template); var inputParams = Map.of("language", "Italian", "input", "Cloud ERP systems"); @@ -1328,7 +1328,7 @@ void testTemplateFromPromptRegistryByScenarioTenant() throws IOException { .withHeader("Content-Type", "application/json"))); var template = - TemplateConfig.referenceTenant().byScenario("test").name("test").version("0.0.1"); + TemplateConfig.reference().byScenario("test").name("test").version("0.0.1"); var configWithTemplate = config.withTemplateConfig(template); var inputParams = Map.of("language", "Italian", "input", "Cloud ERP systems"); 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 e8cc455e8..6a3da1d58 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 @@ -561,7 +561,7 @@ public OrchestrationChatResponse templateFromPromptRegistryByIdTenant( new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); val template = - TemplateConfig.referenceTenant().byIdTenant("21cb1358-0bf1-4f43-870b-00f14d0f9f16"); + TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16"); val configWithTemplate = llmWithImageSupportConfig.withTemplateConfig(template); val inputParams = Map.of("language", "Italian", "input", topic); @@ -613,7 +613,7 @@ public OrchestrationChatResponse templateFromPromptRegistryByIdResourceGroup( public OrchestrationChatResponse templateFromPromptRegistryByScenarioTenant( @Nonnull final String topic) { val template = - TemplateConfig.referenceTenant().byScenario("test").name("test").version("0.0.1"); + TemplateConfig.reference().byScenario("test").name("test").version("0.0.1"); val configWithTemplate = config.withTemplateConfig(template); val inputParams = Map.of("language", "Italian", "input", topic); From 3c6f4e046b86b50b57f33cc6678844b1eb7ae63a Mon Sep 17 00:00:00 2001 From: SAP Cloud SDK Bot Date: Wed, 21 Jan 2026 15:44:53 +0000 Subject: [PATCH 07/15] Formatting --- .../com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java | 6 ++---- .../com/sap/ai/sdk/app/services/OrchestrationService.java | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java index 2ffa5e1ee..b7169ad86 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java @@ -1268,8 +1268,7 @@ void testTemplateFromPromptRegistryByIdTenant() throws IOException { .withBodyFile("templateReferenceResponse.json") .withHeader("Content-Type", "application/json"))); - var template = - TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16"); + var template = TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16"); var configWithTemplate = config.withTemplateConfig(template); var inputParams = Map.of("language", "Italian", "input", "Cloud ERP systems"); @@ -1327,8 +1326,7 @@ void testTemplateFromPromptRegistryByScenarioTenant() throws IOException { .withBodyFile("templateReferenceResponse.json") .withHeader("Content-Type", "application/json"))); - var template = - TemplateConfig.reference().byScenario("test").name("test").version("0.0.1"); + var template = TemplateConfig.reference().byScenario("test").name("test").version("0.0.1"); var configWithTemplate = config.withTemplateConfig(template); var inputParams = Map.of("language", "Italian", "input", "Cloud ERP systems"); 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 6a3da1d58..93e37674b 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 @@ -560,8 +560,7 @@ public OrchestrationChatResponse templateFromPromptRegistryByIdTenant( final var llmWithImageSupportConfig = new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); - val template = - TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16"); + val template = TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16"); val configWithTemplate = llmWithImageSupportConfig.withTemplateConfig(template); val inputParams = Map.of("language", "Italian", "input", topic); @@ -612,8 +611,7 @@ public OrchestrationChatResponse templateFromPromptRegistryByIdResourceGroup( @Nonnull public OrchestrationChatResponse templateFromPromptRegistryByScenarioTenant( @Nonnull final String topic) { - val template = - TemplateConfig.reference().byScenario("test").name("test").version("0.0.1"); + val template = TemplateConfig.reference().byScenario("test").name("test").version("0.0.1"); val configWithTemplate = config.withTemplateConfig(template); val inputParams = Map.of("language", "Italian", "input", topic); From 3b97f7ceb1ab9c994b567200bbb2d2edf4916926 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Wed, 21 Jan 2026 17:46:14 +0100 Subject: [PATCH 08/15] Changing RG id + minor format --- core-services/prompt-registry/pom.xml | 4 ++-- .../com/sap/ai/sdk/orchestration/TemplateConfig.java | 6 ++---- .../ai/sdk/orchestration/OrchestrationUnitTest.java | 2 +- .../templateReferenceResourceGroupResponse.json | 10 +++++----- .../templateReferenceResourceGroupByIdRequest.json | 2 +- .../sap/ai/sdk/app/services/OrchestrationService.java | 6 +++--- 6 files changed, 14 insertions(+), 16 deletions(-) diff --git a/core-services/prompt-registry/pom.xml b/core-services/prompt-registry/pom.xml index 1493c0c49..73f879e58 100644 --- a/core-services/prompt-registry/pom.xml +++ b/core-services/prompt-registry/pom.xml @@ -38,10 +38,10 @@ ${project.basedir}/../../ - 84% + 73% 90% 92% - 100% + 78% 80% 100% diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java index 2436d0702..19ad6ce8b 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java @@ -42,13 +42,11 @@ public static OrchestrationTemplate create() { @Nonnull public static ReferenceBuilder reference() { final var templ = TemplateRefByScenarioNameVersion.create(); - final var scope = TemplateRefByScenarioNameVersion.ScopeEnum.TENANT; + final var sc = TemplateRefByScenarioNameVersion.ScopeEnum.TENANT; return s -> n -> - v -> - new OrchestrationTemplateReference( - templ.scenario(s).name(n).version(v).scope(scope)); + v -> new OrchestrationTemplateReference(templ.scenario(s).name(n).version(v).scope(sc)); } /** diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java index b7169ad86..7489ae2bb 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java @@ -1296,7 +1296,7 @@ void testTemplateFromPromptRegistryByIdResourceGroup() throws IOException { var template = TemplateConfig.referenceResourceGroup() - .byIdResourceGroup("2cd4aea1-dffb-4d5d-b96d-96e29b595025"); + .byIdResourceGroup("8bf72116-11ab-41bb-8933-8be56f59cb67"); var configWithTemplate = config.withLlmConfig(GPT_4O_MINI).withTemplateConfig(template); var inputParams = diff --git a/orchestration/src/test/resources/__files/templateReferenceResourceGroupResponse.json b/orchestration/src/test/resources/__files/templateReferenceResourceGroupResponse.json index 34017f89a..d6a922874 100644 --- a/orchestration/src/test/resources/__files/templateReferenceResourceGroupResponse.json +++ b/orchestration/src/test/resources/__files/templateReferenceResourceGroupResponse.json @@ -1,5 +1,5 @@ { - "request_id": "176cbc1e-7451-9b78-bb3e-278abd576a66", + "request_id": "3e1e6d3f-efa8-942a-8106-6442e42f0f6c", "intermediate_results": { "templating": [ { @@ -12,9 +12,9 @@ } ], "llm": { - "id": "chatcmpl-D09WL0JIzGaEF1RwbaTKitAspDKhO", + "id": "chatcmpl-D0VWJHDekyp5CMGNyrOjAFLgdaktE", "object": "chat.completion", - "created": 1768928969, + "created": 1769013535, "model": "gpt-4o-mini-2024-07-18", "system_fingerprint": "fp_f97eff32c5", "choices": [ @@ -45,9 +45,9 @@ } }, "final_result": { - "id": "chatcmpl-D09WL0JIzGaEF1RwbaTKitAspDKhO", + "id": "chatcmpl-D0VWJHDekyp5CMGNyrOjAFLgdaktE", "object": "chat.completion", - "created": 1768928969, + "created": 1769013535, "model": "gpt-4o-mini-2024-07-18", "system_fingerprint": "fp_f97eff32c5", "choices": [ diff --git a/orchestration/src/test/resources/templateReferenceResourceGroupByIdRequest.json b/orchestration/src/test/resources/templateReferenceResourceGroupByIdRequest.json index 0dad3f949..7dcb96abf 100644 --- a/orchestration/src/test/resources/templateReferenceResourceGroupByIdRequest.json +++ b/orchestration/src/test/resources/templateReferenceResourceGroupByIdRequest.json @@ -4,7 +4,7 @@ "prompt_templating": { "prompt": { "template_ref": { - "id": "2cd4aea1-dffb-4d5d-b96d-96e29b595025", + "id": "8bf72116-11ab-41bb-8933-8be56f59cb67", "scope": "resource_group" } }, 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 93e37674b..6fbd27922 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 @@ -585,12 +585,12 @@ public OrchestrationChatResponse templateFromPromptRegistryByIdResourceGroup( new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); final var destination = - new AiCoreService().getInferenceDestination("i749902").forScenario("orchestration"); + new AiCoreService().getInferenceDestination("ai-sdk-java-e2e").forScenario("orchestration"); final var clientWithResourceGroup = new OrchestrationClient(destination); val template = TemplateConfig.referenceResourceGroup() - .byIdResourceGroup("2cd4aea1-dffb-4d5d-b96d-96e29b595025"); + .byIdResourceGroup("8bf72116-11ab-41bb-8933-8be56f59cb67"); val configWithTemplate = llmWithImageSupportConfig.withTemplateConfig(template); val inputParams = Map.of("categories", "Finance, Tech, Sports", "inputExample", inputExample); @@ -633,7 +633,7 @@ public OrchestrationChatResponse templateFromPromptRegistryByScenarioTenant( public OrchestrationChatResponse templateFromPromptRegistryByScenarioResourceGroup( @Nonnull final String inputExample) { final var destination = - new AiCoreService().getInferenceDestination("i749902").forScenario("orchestration"); + new AiCoreService().getInferenceDestination("ai-sdk-java-e2e").forScenario("orchestration"); final var clientWithResourceGroup = new OrchestrationClient(destination); val template = From abdd0fb6b2756f40c1b64365accf76f775101851 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Thu, 22 Jan 2026 17:35:16 +0100 Subject: [PATCH 09/15] Changing API Approach --- .../OrchestrationTemplateReference.java | 23 +++++++++- .../ai/sdk/orchestration/TemplateConfig.java | 42 ++++--------------- .../OrchestrationConvenienceUnitTest.java | 23 +++++----- .../orchestration/OrchestrationUnitTest.java | 9 ++-- .../app/services/OrchestrationService.java | 12 ++++-- 5 files changed, 55 insertions(+), 54 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationTemplateReference.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationTemplateReference.java index e88ac06a3..27a91d00f 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationTemplateReference.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationTemplateReference.java @@ -3,12 +3,15 @@ import com.google.common.annotations.Beta; import com.sap.ai.sdk.orchestration.model.PromptTemplatingModuleConfigPrompt; import com.sap.ai.sdk.orchestration.model.TemplateRef; +import com.sap.ai.sdk.orchestration.model.TemplateRefByID; +import com.sap.ai.sdk.orchestration.model.TemplateRefByScenarioNameVersion; import com.sap.ai.sdk.orchestration.model.TemplateRefTemplateRef; import javax.annotation.Nonnull; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Value; +import lombok.With; /** * A reference to a template to use in {@link OrchestrationModuleConfig}. @@ -22,6 +25,8 @@ public class OrchestrationTemplateReference extends TemplateConfig { @Nonnull TemplateRefTemplateRef reference; + @With @Nonnull ScopeEnum scope; + /** * Create a low-level representation of the template. * @@ -30,6 +35,22 @@ public class OrchestrationTemplateReference extends TemplateConfig { @Nonnull @Override protected PromptTemplatingModuleConfigPrompt toLowLevel() { - return TemplateRef.create().templateRef(reference); + if (reference instanceof TemplateRefByID idRef) { + final var valueById = TemplateRefByID.ScopeEnum.valueOf(scope.name()); + idRef.setScope(valueById); + return TemplateRef.create().templateRef(idRef); + } else if (reference instanceof TemplateRefByScenarioNameVersion scenarioRef) { + final var valueByScenario = TemplateRefByScenarioNameVersion.ScopeEnum.valueOf(scope.name()); + scenarioRef.setScope(valueByScenario); + return TemplateRef.create().templateRef(scenarioRef); + } else { + throw new IllegalStateException( + "Unsupported template reference type: " + reference.getClass()); + } + } + + public enum ScopeEnum { + TENANT, + RESOURCE_GROUP } } diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java index 19ad6ce8b..fdcd483a1 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java @@ -7,6 +7,8 @@ import javax.annotation.Nonnull; import lombok.EqualsAndHashCode; +import static com.sap.ai.sdk.orchestration.OrchestrationTemplateReference.ScopeEnum.TENANT; + /** * Template configuration for the {@link OrchestrationModuleConfig}. * @@ -42,28 +44,12 @@ public static OrchestrationTemplate create() { @Nonnull public static ReferenceBuilder reference() { final var templ = TemplateRefByScenarioNameVersion.create(); - final var sc = TemplateRefByScenarioNameVersion.ScopeEnum.TENANT; - - return s -> - n -> - v -> new OrchestrationTemplateReference(templ.scenario(s).name(n).version(v).scope(sc)); - } - - /** - * Build a template reference with resource group scope. - * - * @return An intermediate object to build the template reference. - */ - @Nonnull - public static ReferenceBuilder referenceResourceGroup() { - final var templ = TemplateRefByScenarioNameVersion.create(); - final var scope = TemplateRefByScenarioNameVersion.ScopeEnum.RESOURCE_GROUP; - return s -> - n -> - v -> + return scenario -> + name -> + version -> new OrchestrationTemplateReference( - templ.scenario(s).name(n).version(v).scope(scope)); + templ.scenario(scenario).name(name).version(version), TENANT); } /** Intermediate object to build a template reference. */ @@ -77,20 +63,8 @@ public interface ReferenceBuilder { */ @Nonnull default OrchestrationTemplateReference byId(@Nonnull final String id) { - final var scope = TemplateRefByID.ScopeEnum.TENANT; - return new OrchestrationTemplateReference(TemplateRefByID.create().id(id).scope(scope)); - } - - /** - * Build a template reference with the given id for resource group scope. - * - * @param id The id of the template. - * @return A template reference with the given id. - */ - @Nonnull - default OrchestrationTemplateReference byIdResourceGroup(@Nonnull final String id) { - final var scope = TemplateRefByID.ScopeEnum.RESOURCE_GROUP; - return new OrchestrationTemplateReference(TemplateRefByID.create().id(id).scope(scope)); + return new OrchestrationTemplateReference( + TemplateRefByID.create().id(id), TENANT); } /** diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java index 0fc35350f..b2da4264a 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java @@ -1,5 +1,7 @@ package com.sap.ai.sdk.orchestration; +import static com.sap.ai.sdk.orchestration.OrchestrationTemplateReference.ScopeEnum.RESOURCE_GROUP; +import static com.sap.ai.sdk.orchestration.OrchestrationTemplateReference.ScopeEnum.TENANT; import static com.sap.ai.sdk.orchestration.model.UserChatMessage.RoleEnum.USER; import static org.assertj.core.api.Assertions.assertThat; @@ -160,29 +162,29 @@ void testTemplateConstruction() { void testTemplateReferenceConstruction() { var templateReferenceId = TemplateConfig.reference().byId("id"); var expectedTemplateReferenceId = - new OrchestrationTemplateReference(TemplateRefByID.create().id("id")); + new OrchestrationTemplateReference(TemplateRefByID.create().id("id"), TENANT); var templateReferenceIdLowLevel = TemplateRef.create().templateRef(TemplateRefByID.create().id("id")); assertThat(templateReferenceId).isEqualTo(expectedTemplateReferenceId); assertThat(templateReferenceId.toLowLevel()).isEqualTo(templateReferenceIdLowLevel); - templateReferenceId = TemplateConfig.referenceResourceGroup().byIdResourceGroup("id"); - var scope = TemplateRefByID.ScopeEnum.RESOURCE_GROUP; + templateReferenceId = TemplateConfig.reference().byId("id").withScope(RESOURCE_GROUP); expectedTemplateReferenceId = - new OrchestrationTemplateReference(TemplateRefByID.create().id("id").scope(scope)); + new OrchestrationTemplateReference(TemplateRefByID.create().id("id"), RESOURCE_GROUP); templateReferenceIdLowLevel = - TemplateRef.create().templateRef(TemplateRefByID.create().id("id").scope(scope)); + TemplateRef.create().templateRef(TemplateRefByID.create().id("id").scope( + TemplateRefByID.ScopeEnum.RESOURCE_GROUP)); assertThat(templateReferenceId).isEqualTo(expectedTemplateReferenceId); assertThat(templateReferenceId.toLowLevel()).isEqualTo(templateReferenceIdLowLevel); var templateReferenceScenarioNameVersion = - TemplateConfig.reference().byScenario("scenario").name("name").version("version"); + TemplateConfig.reference().byScenario("scenario").name("name").version("version").withScope(TENANT); var expectedTemplateReferenceScenarioNameVersion = new OrchestrationTemplateReference( TemplateRefByScenarioNameVersion.create() .scenario("scenario") .name("name") - .version("version")); + .version("version"), TENANT); var templateReferenceScenarioNameVersionLowLevel = TemplateRef.create() .templateRef( @@ -196,18 +198,17 @@ void testTemplateReferenceConstruction() { .isEqualTo(templateReferenceScenarioNameVersionLowLevel); templateReferenceScenarioNameVersion = - TemplateConfig.referenceResourceGroup() + TemplateConfig.reference() .byScenario("scenario") .name("name") - .version("version"); + .version("version").withScope(RESOURCE_GROUP); var scopeScenario = TemplateRefByScenarioNameVersion.ScopeEnum.RESOURCE_GROUP; expectedTemplateReferenceScenarioNameVersion = new OrchestrationTemplateReference( TemplateRefByScenarioNameVersion.create() .scenario("scenario") .name("name") - .version("version") - .scope(scopeScenario)); + .version("version"), RESOURCE_GROUP); templateReferenceScenarioNameVersionLowLevel = TemplateRef.create() .templateRef( diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java index 7489ae2bb..bc6c62cc1 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java @@ -20,6 +20,7 @@ import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.GPT_4O; import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.GPT_4O_MINI; import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.Parameter.*; +import static com.sap.ai.sdk.orchestration.OrchestrationTemplateReference.ScopeEnum.RESOURCE_GROUP; import static com.sap.ai.sdk.orchestration.model.AzureThreshold.NUMBER_0; import static com.sap.ai.sdk.orchestration.model.AzureThreshold.NUMBER_4; import static com.sap.ai.sdk.orchestration.model.AzureThreshold.NUMBER_6; @@ -1295,8 +1296,7 @@ void testTemplateFromPromptRegistryByIdResourceGroup() throws IOException { .withHeader("Content-Type", "application/json"))); var template = - TemplateConfig.referenceResourceGroup() - .byIdResourceGroup("8bf72116-11ab-41bb-8933-8be56f59cb67"); + TemplateConfig.reference().byId("8bf72116-11ab-41bb-8933-8be56f59cb67").withScope(RESOURCE_GROUP); var configWithTemplate = config.withLlmConfig(GPT_4O_MINI).withTemplateConfig(template); var inputParams = @@ -1350,10 +1350,11 @@ void testTemplateFromPromptRegistryByScenarioResourceGroup() throws IOException .withHeader("Content-Type", "application/json"))); var template = - TemplateConfig.referenceResourceGroup() + TemplateConfig.reference() .byScenario("categorization") .name("example-prompt-template") - .version("0.0.1"); + .version("0.0.1") + .withScope(RESOURCE_GROUP); var configWithTemplate = config.withLlmConfig(GPT_4O_MINI).withTemplateConfig(template); var inputParams = 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 6fbd27922..379e6b0c7 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 @@ -5,6 +5,7 @@ import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.GPT_4O_MINI; import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.Parameter.TEMPERATURE; import static com.sap.ai.sdk.orchestration.OrchestrationEmbeddingModel.TEXT_EMBEDDING_3_SMALL; +import static com.sap.ai.sdk.orchestration.OrchestrationTemplateReference.ScopeEnum.RESOURCE_GROUP; import com.fasterxml.jackson.annotation.JsonProperty; import com.sap.ai.sdk.core.AiCoreService; @@ -23,6 +24,7 @@ import com.sap.ai.sdk.orchestration.OrchestrationEmbeddingResponse; import com.sap.ai.sdk.orchestration.OrchestrationModuleConfig; import com.sap.ai.sdk.orchestration.OrchestrationPrompt; +import com.sap.ai.sdk.orchestration.OrchestrationTemplateReference; import com.sap.ai.sdk.orchestration.ResponseJsonSchema; import com.sap.ai.sdk.orchestration.SystemMessage; import com.sap.ai.sdk.orchestration.TemplateConfig; @@ -589,8 +591,9 @@ public OrchestrationChatResponse templateFromPromptRegistryByIdResourceGroup( final var clientWithResourceGroup = new OrchestrationClient(destination); val template = - TemplateConfig.referenceResourceGroup() - .byIdResourceGroup("8bf72116-11ab-41bb-8933-8be56f59cb67"); + TemplateConfig.reference() + .byId("8bf72116-11ab-41bb-8933-8be56f59cb67") + .withScope(RESOURCE_GROUP); val configWithTemplate = llmWithImageSupportConfig.withTemplateConfig(template); val inputParams = Map.of("categories", "Finance, Tech, Sports", "inputExample", inputExample); @@ -637,10 +640,11 @@ public OrchestrationChatResponse templateFromPromptRegistryByScenarioResourceGro final var clientWithResourceGroup = new OrchestrationClient(destination); val template = - TemplateConfig.referenceResourceGroup() + TemplateConfig.reference() .byScenario("categorization") .name("example-prompt-template") - .version("0.0.1"); + .version("0.0.1") + .withScope(RESOURCE_GROUP); val configWithTemplate = config.withTemplateConfig(template); val inputParams = Map.of("categories", "Finance, Tech, Sports", "inputExample", inputExample); From 89c6f968804b41f6f5cda843459bca9119d46181 Mon Sep 17 00:00:00 2001 From: SAP Cloud SDK Bot Date: Thu, 22 Jan 2026 16:36:05 +0000 Subject: [PATCH 10/15] Formatting --- .../ai/sdk/orchestration/TemplateConfig.java | 7 +++---- .../OrchestrationConvenienceUnitTest.java | 20 +++++++++++++------ .../orchestration/OrchestrationUnitTest.java | 4 +++- .../app/services/OrchestrationService.java | 1 - 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java index fdcd483a1..f0a328e97 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java @@ -1,5 +1,7 @@ package com.sap.ai.sdk.orchestration; +import static com.sap.ai.sdk.orchestration.OrchestrationTemplateReference.ScopeEnum.TENANT; + import com.google.common.annotations.Beta; import com.sap.ai.sdk.orchestration.model.PromptTemplatingModuleConfigPrompt; import com.sap.ai.sdk.orchestration.model.TemplateRefByID; @@ -7,8 +9,6 @@ import javax.annotation.Nonnull; import lombok.EqualsAndHashCode; -import static com.sap.ai.sdk.orchestration.OrchestrationTemplateReference.ScopeEnum.TENANT; - /** * Template configuration for the {@link OrchestrationModuleConfig}. * @@ -63,8 +63,7 @@ public interface ReferenceBuilder { */ @Nonnull default OrchestrationTemplateReference byId(@Nonnull final String id) { - return new OrchestrationTemplateReference( - TemplateRefByID.create().id(id), TENANT); + return new OrchestrationTemplateReference(TemplateRefByID.create().id(id), TENANT); } /** diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java index b2da4264a..da26e2adb 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java @@ -172,19 +172,25 @@ void testTemplateReferenceConstruction() { expectedTemplateReferenceId = new OrchestrationTemplateReference(TemplateRefByID.create().id("id"), RESOURCE_GROUP); templateReferenceIdLowLevel = - TemplateRef.create().templateRef(TemplateRefByID.create().id("id").scope( - TemplateRefByID.ScopeEnum.RESOURCE_GROUP)); + TemplateRef.create() + .templateRef( + TemplateRefByID.create().id("id").scope(TemplateRefByID.ScopeEnum.RESOURCE_GROUP)); assertThat(templateReferenceId).isEqualTo(expectedTemplateReferenceId); assertThat(templateReferenceId.toLowLevel()).isEqualTo(templateReferenceIdLowLevel); var templateReferenceScenarioNameVersion = - TemplateConfig.reference().byScenario("scenario").name("name").version("version").withScope(TENANT); + TemplateConfig.reference() + .byScenario("scenario") + .name("name") + .version("version") + .withScope(TENANT); var expectedTemplateReferenceScenarioNameVersion = new OrchestrationTemplateReference( TemplateRefByScenarioNameVersion.create() .scenario("scenario") .name("name") - .version("version"), TENANT); + .version("version"), + TENANT); var templateReferenceScenarioNameVersionLowLevel = TemplateRef.create() .templateRef( @@ -201,14 +207,16 @@ void testTemplateReferenceConstruction() { TemplateConfig.reference() .byScenario("scenario") .name("name") - .version("version").withScope(RESOURCE_GROUP); + .version("version") + .withScope(RESOURCE_GROUP); var scopeScenario = TemplateRefByScenarioNameVersion.ScopeEnum.RESOURCE_GROUP; expectedTemplateReferenceScenarioNameVersion = new OrchestrationTemplateReference( TemplateRefByScenarioNameVersion.create() .scenario("scenario") .name("name") - .version("version"), RESOURCE_GROUP); + .version("version"), + RESOURCE_GROUP); templateReferenceScenarioNameVersionLowLevel = TemplateRef.create() .templateRef( diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java index bc6c62cc1..30b159236 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java @@ -1296,7 +1296,9 @@ void testTemplateFromPromptRegistryByIdResourceGroup() throws IOException { .withHeader("Content-Type", "application/json"))); var template = - TemplateConfig.reference().byId("8bf72116-11ab-41bb-8933-8be56f59cb67").withScope(RESOURCE_GROUP); + TemplateConfig.reference() + .byId("8bf72116-11ab-41bb-8933-8be56f59cb67") + .withScope(RESOURCE_GROUP); var configWithTemplate = config.withLlmConfig(GPT_4O_MINI).withTemplateConfig(template); var inputParams = 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 379e6b0c7..4ef4e7122 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 @@ -24,7 +24,6 @@ import com.sap.ai.sdk.orchestration.OrchestrationEmbeddingResponse; import com.sap.ai.sdk.orchestration.OrchestrationModuleConfig; import com.sap.ai.sdk.orchestration.OrchestrationPrompt; -import com.sap.ai.sdk.orchestration.OrchestrationTemplateReference; import com.sap.ai.sdk.orchestration.ResponseJsonSchema; import com.sap.ai.sdk.orchestration.SystemMessage; import com.sap.ai.sdk.orchestration.TemplateConfig; From f6ea67a5d820db08c9af1693cbc90d9b27eb51b7 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Thu, 22 Jan 2026 17:42:37 +0100 Subject: [PATCH 11/15] Adding JavaDocs + Formatting --- .../OrchestrationTemplateReference.java | 3 +++ .../ai/sdk/orchestration/TemplateConfig.java | 7 +++---- .../OrchestrationConvenienceUnitTest.java | 20 +++++++++++++------ .../orchestration/OrchestrationUnitTest.java | 4 +++- .../app/services/OrchestrationService.java | 1 - 5 files changed, 23 insertions(+), 12 deletions(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationTemplateReference.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationTemplateReference.java index 27a91d00f..1acd89eee 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationTemplateReference.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationTemplateReference.java @@ -49,8 +49,11 @@ protected PromptTemplatingModuleConfigPrompt toLowLevel() { } } + /** The scope of the template reference. */ public enum ScopeEnum { + /** Template is resolved within the current tenant scope. */ TENANT, + /** Template is resolved within the configured resource group scope. */ RESOURCE_GROUP } } diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java index fdcd483a1..f0a328e97 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/TemplateConfig.java @@ -1,5 +1,7 @@ package com.sap.ai.sdk.orchestration; +import static com.sap.ai.sdk.orchestration.OrchestrationTemplateReference.ScopeEnum.TENANT; + import com.google.common.annotations.Beta; import com.sap.ai.sdk.orchestration.model.PromptTemplatingModuleConfigPrompt; import com.sap.ai.sdk.orchestration.model.TemplateRefByID; @@ -7,8 +9,6 @@ import javax.annotation.Nonnull; import lombok.EqualsAndHashCode; -import static com.sap.ai.sdk.orchestration.OrchestrationTemplateReference.ScopeEnum.TENANT; - /** * Template configuration for the {@link OrchestrationModuleConfig}. * @@ -63,8 +63,7 @@ public interface ReferenceBuilder { */ @Nonnull default OrchestrationTemplateReference byId(@Nonnull final String id) { - return new OrchestrationTemplateReference( - TemplateRefByID.create().id(id), TENANT); + return new OrchestrationTemplateReference(TemplateRefByID.create().id(id), TENANT); } /** diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java index b2da4264a..da26e2adb 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationConvenienceUnitTest.java @@ -172,19 +172,25 @@ void testTemplateReferenceConstruction() { expectedTemplateReferenceId = new OrchestrationTemplateReference(TemplateRefByID.create().id("id"), RESOURCE_GROUP); templateReferenceIdLowLevel = - TemplateRef.create().templateRef(TemplateRefByID.create().id("id").scope( - TemplateRefByID.ScopeEnum.RESOURCE_GROUP)); + TemplateRef.create() + .templateRef( + TemplateRefByID.create().id("id").scope(TemplateRefByID.ScopeEnum.RESOURCE_GROUP)); assertThat(templateReferenceId).isEqualTo(expectedTemplateReferenceId); assertThat(templateReferenceId.toLowLevel()).isEqualTo(templateReferenceIdLowLevel); var templateReferenceScenarioNameVersion = - TemplateConfig.reference().byScenario("scenario").name("name").version("version").withScope(TENANT); + TemplateConfig.reference() + .byScenario("scenario") + .name("name") + .version("version") + .withScope(TENANT); var expectedTemplateReferenceScenarioNameVersion = new OrchestrationTemplateReference( TemplateRefByScenarioNameVersion.create() .scenario("scenario") .name("name") - .version("version"), TENANT); + .version("version"), + TENANT); var templateReferenceScenarioNameVersionLowLevel = TemplateRef.create() .templateRef( @@ -201,14 +207,16 @@ void testTemplateReferenceConstruction() { TemplateConfig.reference() .byScenario("scenario") .name("name") - .version("version").withScope(RESOURCE_GROUP); + .version("version") + .withScope(RESOURCE_GROUP); var scopeScenario = TemplateRefByScenarioNameVersion.ScopeEnum.RESOURCE_GROUP; expectedTemplateReferenceScenarioNameVersion = new OrchestrationTemplateReference( TemplateRefByScenarioNameVersion.create() .scenario("scenario") .name("name") - .version("version"), RESOURCE_GROUP); + .version("version"), + RESOURCE_GROUP); templateReferenceScenarioNameVersionLowLevel = TemplateRef.create() .templateRef( diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java index bc6c62cc1..30b159236 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java @@ -1296,7 +1296,9 @@ void testTemplateFromPromptRegistryByIdResourceGroup() throws IOException { .withHeader("Content-Type", "application/json"))); var template = - TemplateConfig.reference().byId("8bf72116-11ab-41bb-8933-8be56f59cb67").withScope(RESOURCE_GROUP); + TemplateConfig.reference() + .byId("8bf72116-11ab-41bb-8933-8be56f59cb67") + .withScope(RESOURCE_GROUP); var configWithTemplate = config.withLlmConfig(GPT_4O_MINI).withTemplateConfig(template); var inputParams = 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 379e6b0c7..4ef4e7122 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 @@ -24,7 +24,6 @@ import com.sap.ai.sdk.orchestration.OrchestrationEmbeddingResponse; import com.sap.ai.sdk.orchestration.OrchestrationModuleConfig; import com.sap.ai.sdk.orchestration.OrchestrationPrompt; -import com.sap.ai.sdk.orchestration.OrchestrationTemplateReference; import com.sap.ai.sdk.orchestration.ResponseJsonSchema; import com.sap.ai.sdk.orchestration.SystemMessage; import com.sap.ai.sdk.orchestration.TemplateConfig; From 66b27ed792f7eff2764d9704f588cc37169fd39d Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Mon, 26 Jan 2026 12:00:18 +0100 Subject: [PATCH 12/15] Removing LLM with Image Support --- .../orchestration/OrchestrationUnitTest.java | 10 ++++- ...emplateReferenceResourceGroupResponse.json | 40 +++++++------------ ...lateReferenceResourceGroupByIdRequest.json | 6 ++- ...ferenceResourceGroupByScenarioRequest.json | 6 ++- .../app/services/OrchestrationService.java | 4 +- 5 files changed, 32 insertions(+), 34 deletions(-) diff --git a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java index 30b159236..2d6ba8811 100644 --- a/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java +++ b/orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java @@ -17,6 +17,7 @@ import static com.github.tomakehurst.wiremock.client.WireMock.verify; import static com.sap.ai.sdk.orchestration.AzureFilterThreshold.ALLOW_SAFE; import static com.sap.ai.sdk.orchestration.AzureFilterThreshold.ALLOW_SAFE_LOW_MEDIUM; +import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.GEMINI_2_5_FLASH; import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.GPT_4O; import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.GPT_4O_MINI; import static com.sap.ai.sdk.orchestration.OrchestrationAiModel.Parameter.*; @@ -1299,7 +1300,10 @@ void testTemplateFromPromptRegistryByIdResourceGroup() throws IOException { TemplateConfig.reference() .byId("8bf72116-11ab-41bb-8933-8be56f59cb67") .withScope(RESOURCE_GROUP); - var configWithTemplate = config.withLlmConfig(GPT_4O_MINI).withTemplateConfig(template); + var config = + new OrchestrationModuleConfig() + .withLlmConfig(GEMINI_2_5_FLASH.withParam(TEMPERATURE, 0.0)); + var configWithTemplate = config.withTemplateConfig(template); var inputParams = Map.of( @@ -1357,7 +1361,9 @@ void testTemplateFromPromptRegistryByScenarioResourceGroup() throws IOException .name("example-prompt-template") .version("0.0.1") .withScope(RESOURCE_GROUP); - var configWithTemplate = config.withLlmConfig(GPT_4O_MINI).withTemplateConfig(template); + var config = + new OrchestrationModuleConfig().withLlmConfig(GEMINI_2_5_FLASH.withParam(TEMPERATURE, 0.0)); + var configWithTemplate = config.withTemplateConfig(template); var inputParams = Map.of( diff --git a/orchestration/src/test/resources/__files/templateReferenceResourceGroupResponse.json b/orchestration/src/test/resources/__files/templateReferenceResourceGroupResponse.json index d6a922874..25ba4607a 100644 --- a/orchestration/src/test/resources/__files/templateReferenceResourceGroupResponse.json +++ b/orchestration/src/test/resources/__files/templateReferenceResourceGroupResponse.json @@ -1,5 +1,5 @@ { - "request_id": "3e1e6d3f-efa8-942a-8106-6442e42f0f6c", + "request_id": "921f38b7-3434-9171-85df-27be1b7fca3c", "intermediate_results": { "templating": [ { @@ -12,11 +12,10 @@ } ], "llm": { - "id": "chatcmpl-D0VWJHDekyp5CMGNyrOjAFLgdaktE", + "id": "", "object": "chat.completion", - "created": 1769013535, - "model": "gpt-4o-mini-2024-07-18", - "system_fingerprint": "fp_f97eff32c5", + "created": 1769424215, + "model": "gemini-2.5-flash", "choices": [ { "index": 0, @@ -28,28 +27,23 @@ } ], "usage": { - "completion_tokens": 2, - "prompt_tokens": 35, - "total_tokens": 37, + "completion_tokens": 154, + "prompt_tokens": 26, + "total_tokens": 180, "prompt_tokens_details": { - "audio_tokens": 0, "cached_tokens": 0 }, "completion_tokens_details": { - "accepted_prediction_tokens": 0, - "audio_tokens": 0, - "reasoning_tokens": 0, - "rejected_prediction_tokens": 0 + "reasoning_tokens": 153 } } } }, "final_result": { - "id": "chatcmpl-D0VWJHDekyp5CMGNyrOjAFLgdaktE", + "id": "", "object": "chat.completion", - "created": 1769013535, - "model": "gpt-4o-mini-2024-07-18", - "system_fingerprint": "fp_f97eff32c5", + "created": 1769424215, + "model": "gemini-2.5-flash", "choices": [ { "index": 0, @@ -61,18 +55,14 @@ } ], "usage": { - "completion_tokens": 2, - "prompt_tokens": 35, - "total_tokens": 37, + "completion_tokens": 154, + "prompt_tokens": 26, + "total_tokens": 180, "prompt_tokens_details": { - "audio_tokens": 0, "cached_tokens": 0 }, "completion_tokens_details": { - "accepted_prediction_tokens": 0, - "audio_tokens": 0, - "reasoning_tokens": 0, - "rejected_prediction_tokens": 0 + "reasoning_tokens": 153 } } } diff --git a/orchestration/src/test/resources/templateReferenceResourceGroupByIdRequest.json b/orchestration/src/test/resources/templateReferenceResourceGroupByIdRequest.json index 7dcb96abf..b81565d24 100644 --- a/orchestration/src/test/resources/templateReferenceResourceGroupByIdRequest.json +++ b/orchestration/src/test/resources/templateReferenceResourceGroupByIdRequest.json @@ -9,9 +9,11 @@ } }, "model": { - "name": "gpt-4o-mini", + "name": "gemini-2.5-flash", "version": "latest", - "params": {}, + "params": { + "temperature": 0.0 + }, "timeout": 600, "max_retries": 2 } diff --git a/orchestration/src/test/resources/templateReferenceResourceGroupByScenarioRequest.json b/orchestration/src/test/resources/templateReferenceResourceGroupByScenarioRequest.json index 867f4a13c..625c8ce70 100644 --- a/orchestration/src/test/resources/templateReferenceResourceGroupByScenarioRequest.json +++ b/orchestration/src/test/resources/templateReferenceResourceGroupByScenarioRequest.json @@ -11,9 +11,11 @@ } }, "model": { - "name": "gpt-4o-mini", + "name": "gemini-2.5-flash", "version": "latest", - "params": {}, + "params": { + "temperature": 0.0 + }, "timeout": 600, "max_retries": 2 } 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 4ef4e7122..29e43e4c3 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 @@ -582,8 +582,6 @@ public OrchestrationChatResponse templateFromPromptRegistryByIdTenant( @Nonnull public OrchestrationChatResponse templateFromPromptRegistryByIdResourceGroup( @Nonnull final String inputExample) { - final var llmWithImageSupportConfig = - new OrchestrationModuleConfig().withLlmConfig(GPT_4O_MINI); final var destination = new AiCoreService().getInferenceDestination("ai-sdk-java-e2e").forScenario("orchestration"); @@ -593,7 +591,7 @@ public OrchestrationChatResponse templateFromPromptRegistryByIdResourceGroup( TemplateConfig.reference() .byId("8bf72116-11ab-41bb-8933-8be56f59cb67") .withScope(RESOURCE_GROUP); - val configWithTemplate = llmWithImageSupportConfig.withTemplateConfig(template); + val configWithTemplate = config.withTemplateConfig(template); val inputParams = Map.of("categories", "Finance, Tech, Sports", "inputExample", inputExample); val prompt = new OrchestrationPrompt(inputParams); From acf6003bd4d82dcf194819915d456f98e3fb09c8 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Mon, 26 Jan 2026 13:47:02 +0100 Subject: [PATCH 13/15] Updating 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 5745d6681..7ad885c4e 100644 --- a/docs/release_notes.md +++ b/docs/release_notes.md @@ -16,7 +16,7 @@ ### 📈 Improvements -- +-[Orchestration] Added new API OrchestrationTemplateReference#withScope to support RG-scoped prompt templates. ### 🐛 Fixed Issues From 8c09db82c4d919fa4bf0eeebbc9c0207f0fbcae9 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Mon, 26 Jan 2026 16:56:55 +0100 Subject: [PATCH 14/15] Making exception error message clearer --- .../ai/sdk/orchestration/OrchestrationClientException.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationClientException.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationClientException.java index 3df999b9b..585eaee75 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationClientException.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationClientException.java @@ -29,6 +29,11 @@ public class OrchestrationClientException extends ClientException { (message, clientError, cause) -> { final var details = extractInputFilterDetails(clientError); if (details.isEmpty()) { + if (message.equals( + "Request failed with status 404 (Not Found): 404 - Templating Module: No Prompt Template found in the Prompt Registry.")) { + message += + "\n Please verify that the provided resource group id is correct and matches provided template reference details if the template is on resource-group level, otherwise use tenant scope with no resource group id header."; + } return new OrchestrationClientException(message, cause).setClientError(clientError); } return new Input(message, cause).setFilterDetails(details).setClientError(clientError); From 6787c53e0c36c1f8148596648845725ba6a43671 Mon Sep 17 00:00:00 2001 From: Nourhan Shata Date: Mon, 26 Jan 2026 17:04:16 +0100 Subject: [PATCH 15/15] Making exception error message clearer --- .../sap/ai/sdk/orchestration/OrchestrationClientException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationClientException.java b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationClientException.java index 585eaee75..929ea27a5 100644 --- a/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationClientException.java +++ b/orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationClientException.java @@ -32,7 +32,7 @@ public class OrchestrationClientException extends ClientException { if (message.equals( "Request failed with status 404 (Not Found): 404 - Templating Module: No Prompt Template found in the Prompt Registry.")) { message += - "\n Please verify that the provided resource group id is correct and matches provided template reference details if the template is on resource-group level, otherwise use tenant scope with no resource group id header."; + "\n Please verify that the provided resource group id is correct and matches the provided template reference details if the template is referenced from a resource-group scope, otherwise use the tenant scope without resource group id header."; } return new OrchestrationClientException(message, cause).setClientError(clientError); }