diff --git a/core-services/prompt-registry/pom.xml b/core-services/prompt-registry/pom.xml index e7880ee9d..2738f5849 100644 --- a/core-services/prompt-registry/pom.xml +++ b/core-services/prompt-registry/pom.xml @@ -38,11 +38,11 @@ ${project.basedir}/../../ - 91% + 88% 93% 94% 100% - 83% + 80% 100% @@ -73,10 +73,6 @@ com.fasterxml.jackson.core jackson-core - - com.google.guava - guava - com.fasterxml.jackson.core jackson-annotations diff --git a/core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/OrchestrationConfigClient.java b/core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/OrchestrationConfigMixin.java similarity index 68% rename from core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/OrchestrationConfigClient.java rename to core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/OrchestrationConfigMixin.java index 5a9d1096b..ebbc56d65 100644 --- a/core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/OrchestrationConfigClient.java +++ b/core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/OrchestrationConfigMixin.java @@ -4,9 +4,7 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.google.common.annotations.Beta; import com.sap.ai.sdk.core.AiCoreService; -import com.sap.ai.sdk.prompt.registry.client.OrchestrationConfigsApi; import com.sap.ai.sdk.prompt.registry.model.AzureContentSafetyInputFilterConfig; import com.sap.ai.sdk.prompt.registry.model.AzureContentSafetyOutputFilterConfig; import com.sap.ai.sdk.prompt.registry.model.InputFilterConfig; @@ -18,32 +16,10 @@ import lombok.NoArgsConstructor; import lombok.val; -/** - * Client for managing Orchestration Configurations in the Prompt Registry service. - * - * @since 1.15.0 - */ -@Beta -public class OrchestrationConfigClient extends OrchestrationConfigsApi { - - /** - * Instantiates a client to manage Orchestration Configurations on the Prompt Registry service. - */ - public OrchestrationConfigClient() { - this(new AiCoreService()); - } - - /** - * Instantiates a client to manage Orchestration Configurations on the Prompt Registry service. - * - * @param aiCoreService The configured connectivity instance to AI Core - */ - public OrchestrationConfigClient(@Nonnull final AiCoreService aiCoreService) { - super(addMixin(aiCoreService)); - } +class OrchestrationConfigMixin { @Nonnull - private static ApiClient addMixin(@Nonnull final AiCoreService service) { + static ApiClient addMixin(@Nonnull final AiCoreService service) { final var destination = service.getBaseDestination(); val objectMapper = @@ -54,8 +30,8 @@ private static ApiClient addMixin(@Nonnull final AiCoreService service) { return ApiClient.create(destination).withObjectMapper(objectMapper); } - @NoArgsConstructor(access = AccessLevel.PRIVATE) - private static class JacksonMixin { + @NoArgsConstructor(access = AccessLevel.PACKAGE) + static class JacksonMixin { @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, diff --git a/core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/PromptClient.java b/core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/PromptClientMixin.java similarity index 79% rename from core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/PromptClient.java rename to core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/PromptClientMixin.java index ae252897a..6d2f8652e 100644 --- a/core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/PromptClient.java +++ b/core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/PromptClientMixin.java @@ -11,7 +11,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.sap.ai.sdk.core.AiCoreService; -import com.sap.ai.sdk.prompt.registry.client.PromptTemplatesApi; import com.sap.ai.sdk.prompt.registry.model.MultiChatContent; import com.sap.ai.sdk.prompt.registry.model.MultiChatTemplate; import com.sap.ai.sdk.prompt.registry.model.PromptTemplate; @@ -28,34 +27,10 @@ import lombok.NoArgsConstructor; import lombok.val; -/** - * Client for the Prompt Registry service. - * - * @since 1.6.0 - */ -public class PromptClient extends PromptTemplatesApi { - - /** - * Instantiates this a client to invoke operations on the Prompt Registry service. - * - * @since 1.6.0 - */ - public PromptClient() { - this(new AiCoreService()); - } - - /** - * Instantiates this a client to invoke operations on the Prompt Registry service. - * - * @param aiCoreService The configured connectivity instance to AI Core - * @since 1.6.0 - */ - public PromptClient(@Nonnull final AiCoreService aiCoreService) { - super(addMixin(aiCoreService)); - } +class PromptClientMixin { @Nonnull - private static ApiClient addMixin(@Nonnull final AiCoreService service) { + static ApiClient addMixin(@Nonnull final AiCoreService service) { final var destination = service.getBaseDestination(); val objectMapper = @@ -66,8 +41,8 @@ private static ApiClient addMixin(@Nonnull final AiCoreService service) { return ApiClient.create(destination).withObjectMapper(objectMapper); } - @NoArgsConstructor(access = AccessLevel.PRIVATE) - private static class JacksonMixin { + @NoArgsConstructor(access = AccessLevel.PACKAGE) + static class JacksonMixin { @JsonTypeInfo(use = JsonTypeInfo.Id.NONE) @JsonDeserialize(using = PromptTemplateDeserializer.class) interface TemplateMixIn {} @@ -85,7 +60,7 @@ interface TemplateMixIn {} interface ResponseFormat {} } - private static class PromptTemplateDeserializer extends JsonDeserializer { + static class PromptTemplateDeserializer extends JsonDeserializer { @Override public PromptTemplate deserialize( diff --git a/core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/PromptRegistryClient.java b/core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/PromptRegistryClient.java new file mode 100644 index 000000000..bbf58d0fe --- /dev/null +++ b/core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/PromptRegistryClient.java @@ -0,0 +1,50 @@ +package com.sap.ai.sdk.prompt.registry; + +import com.sap.ai.sdk.core.AiCoreService; +import com.sap.ai.sdk.prompt.registry.client.OrchestrationConfigsApi; +import com.sap.ai.sdk.prompt.registry.client.PromptTemplatesApi; +import javax.annotation.Nonnull; + +/** + * Unified client to use Prompt Registry API + * + * @since 2.0 + */ +public class PromptRegistryClient { + + private final AiCoreService aiCoreService; + + /** Constructs default PromptRegistryClient */ + public PromptRegistryClient() { + this(new AiCoreService()); + } + + /** + * Constructs PromptRegistryClient with customized AiCoreService + * + * @param service customized AiCoreService + */ + public PromptRegistryClient(@Nonnull final AiCoreService service) { + aiCoreService = service; + } + + /** + * Get the prompt templates client + * + * @return the client + */ + @Nonnull + public PromptTemplatesApi prompt() { + return new PromptTemplatesApi(PromptClientMixin.addMixin(aiCoreService)); + } + + /** + * Get the orchestration configs client + * + * @return the client + */ + @Nonnull + public OrchestrationConfigsApi orchestrationConfig() { + return new OrchestrationConfigsApi(OrchestrationConfigMixin.addMixin(aiCoreService)); + } +} diff --git a/core-services/prompt-registry/src/test/java/com/sap/ai/sdk/prompt/registry/OrchestrationConfigClientTest.java b/core-services/prompt-registry/src/test/java/com/sap/ai/sdk/prompt/registry/OrchestrationConfigClientTest.java index 2365d0bdc..f3bd2abbb 100644 --- a/core-services/prompt-registry/src/test/java/com/sap/ai/sdk/prompt/registry/OrchestrationConfigClientTest.java +++ b/core-services/prompt-registry/src/test/java/com/sap/ai/sdk/prompt/registry/OrchestrationConfigClientTest.java @@ -5,10 +5,11 @@ import com.github.tomakehurst.wiremock.junit5.WireMockExtension; import com.sap.ai.sdk.core.AiCoreService; +import com.sap.ai.sdk.prompt.registry.client.OrchestrationConfigsApi; import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination; import com.sap.cloud.sdk.cloudplatform.connectivity.HttpDestination; import java.util.UUID; -import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -17,13 +18,14 @@ public class OrchestrationConfigClientTest { private static final WireMockExtension WM = WireMockExtension.newInstance().options(wireMockConfig().dynamicPort()).build(); - private static OrchestrationConfigClient client; + private static OrchestrationConfigsApi client; - @BeforeEach - void setup() { + @BeforeAll + static void setup() { final HttpDestination destination = DefaultHttpDestination.builder(WM.baseUrl()).build(); final AiCoreService service = new AiCoreService().withBaseDestination(destination); - client = new OrchestrationConfigClient(service); + final var promptRegistryClient = new PromptRegistryClient(service); + client = promptRegistryClient.orchestrationConfig(); } @Test diff --git a/core-services/prompt-registry/src/test/java/com/sap/ai/sdk/prompt/registry/PromptRegistryClientTest.java b/core-services/prompt-registry/src/test/java/com/sap/ai/sdk/prompt/registry/PromptRegistryClientTest.java index b81131c0a..16eea6301 100644 --- a/core-services/prompt-registry/src/test/java/com/sap/ai/sdk/prompt/registry/PromptRegistryClientTest.java +++ b/core-services/prompt-registry/src/test/java/com/sap/ai/sdk/prompt/registry/PromptRegistryClientTest.java @@ -6,6 +6,7 @@ import com.github.tomakehurst.wiremock.junit5.WireMockExtension; import com.sap.ai.sdk.core.AiCoreService; +import com.sap.ai.sdk.prompt.registry.client.PromptTemplatesApi; import com.sap.ai.sdk.prompt.registry.model.MultiChatTemplate; import com.sap.ai.sdk.prompt.registry.model.PromptTemplateGetResponse; import com.sap.ai.sdk.prompt.registry.model.PromptTemplateSubstitutionRequest; @@ -18,7 +19,7 @@ import com.sap.cloud.sdk.cloudplatform.connectivity.HttpDestination; import java.util.Map; import java.util.UUID; -import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; @@ -27,13 +28,14 @@ class PromptRegistryClientTest { private static final WireMockExtension WM = WireMockExtension.newInstance().options(wireMockConfig().dynamicPort()).build(); - private static PromptClient client; + private static PromptTemplatesApi client; - @BeforeEach - void setup() { + @BeforeAll + static void setup() { final HttpDestination destination = DefaultHttpDestination.builder(WM.baseUrl()).build(); final AiCoreService service = new AiCoreService().withBaseDestination(destination); - client = new PromptClient(service); + PromptRegistryClient promptRegistryClient = new PromptRegistryClient(service); + client = promptRegistryClient.prompt(); } @Test diff --git a/core-services/prompt-registry/src/test/java/com/sap/ai/sdk/prompt/registry/spring/SpringAiConverterTest.java b/core-services/prompt-registry/src/test/java/com/sap/ai/sdk/prompt/registry/spring/SpringAiConverterTest.java index 7008efabe..bbf2d63ee 100644 --- a/core-services/prompt-registry/src/test/java/com/sap/ai/sdk/prompt/registry/spring/SpringAiConverterTest.java +++ b/core-services/prompt-registry/src/test/java/com/sap/ai/sdk/prompt/registry/spring/SpringAiConverterTest.java @@ -6,17 +6,18 @@ import com.github.tomakehurst.wiremock.junit5.WireMockExtension; import com.sap.ai.sdk.core.AiCoreService; -import com.sap.ai.sdk.prompt.registry.PromptClient; +import com.sap.ai.sdk.prompt.registry.PromptRegistryClient; +import com.sap.ai.sdk.prompt.registry.client.PromptTemplatesApi; import com.sap.ai.sdk.prompt.registry.model.MultiChatContent; import com.sap.ai.sdk.prompt.registry.model.MultiChatTemplate; import com.sap.ai.sdk.prompt.registry.model.PromptTemplate; import com.sap.ai.sdk.prompt.registry.model.PromptTemplateSubstitutionRequest; import com.sap.ai.sdk.prompt.registry.model.PromptTemplateSubstitutionResponse; import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination; -import com.sap.cloud.sdk.cloudplatform.connectivity.HttpDestination; import java.util.List; import java.util.Map; import lombok.val; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; import org.springframework.ai.chat.messages.Message; @@ -28,12 +29,17 @@ public class SpringAiConverterTest { private static final WireMockExtension WM = WireMockExtension.newInstance().options(wireMockConfig().dynamicPort()).build(); - private final HttpDestination DESTINATION = DefaultHttpDestination.builder(WM.baseUrl()).build(); - private final AiCoreService SERVICE = new AiCoreService().withBaseDestination(DESTINATION); + private static PromptTemplatesApi client; + + @BeforeAll + static void setup() { + val destination = DefaultHttpDestination.builder(WM.baseUrl()).build(); + val service = new AiCoreService().withBaseDestination(destination); + client = new PromptRegistryClient(service).prompt(); + } @Test void testPromptRegistryToSpringAi() { - var client = new PromptClient(SERVICE); val promptResponse = client.parsePromptTemplateByNameVersion( "categorization", @@ -56,7 +62,6 @@ void testPromptRegistryToSpringAi() { @Test void testInvalidRoleThrowsException() { - var client = new PromptClient(SERVICE); val errorPrompt = client.parsePromptTemplateByNameVersion( "categorization", @@ -75,7 +80,6 @@ void testInvalidRoleThrowsException() { @Test void testMultiChatTemplateTextContentToSpringAi() { - var client = new PromptClient(SERVICE); val promptResponse = client.parsePromptTemplateByNameVersion( "categorization", @@ -94,7 +98,6 @@ void testMultiChatTemplateTextContentToSpringAi() { @Test void testMultiChatTemplateImageContentThrowsException() { - var client = new PromptClient(SERVICE); val promptResponse = client.parsePromptTemplateByNameVersion( "categorization", diff --git a/docs/release_notes.md b/docs/release_notes.md index c8381b375..d4505038e 100644 --- a/docs/release_notes.md +++ b/docs/release_notes.md @@ -10,6 +10,30 @@ - [RPT] SAP-RPT was updated to the newer 1.6.0 API - [Orchestration] Spring AI support was upgraded to version `2.0.1` +- [Core] OrchestrationConfigClient and PromptClient were reworked into unified PromptRegistryClient, + see migration guide below for additional information + +#### Prompt registry client Migration Guide + +OrchestrationConfigClient and PromptClient were replaced with unified PromptRegistryClient, + +OrchestrationConfigClient: +```diff +-var orchestrationConfigsClient = new OrchestrationConfigClient(); +-var configs = orchestrationConfigsClient.listOrchestrationConfigs(); + ++var orchestractionConfigsClient = new PromptRegistryClient().orchestrationConfig(); ++var configs = orchestractionConfigsClient.listOrchestrationConfigs(); +``` + +PromptRegistryClient: +```diff +-var promptClient = new PromptClient(); +-var templates = promptClient.listPromptTemplates(); + ++var promptClient = new PromptRegistryClient().prompt(); ++var templates = promptClient.listPromptTemplates(); +``` #### Spring AI 2.0.1 Migration Guide diff --git a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/PromptRegistryController.java b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/PromptRegistryController.java index 097a7c193..a130d425d 100644 --- a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/PromptRegistryController.java +++ b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/PromptRegistryController.java @@ -3,8 +3,9 @@ import com.sap.ai.sdk.foundationmodels.openai.OpenAiClient; import com.sap.ai.sdk.foundationmodels.openai.OpenAiModel; import com.sap.ai.sdk.foundationmodels.openai.spring.OpenAiChatModel; -import com.sap.ai.sdk.prompt.registry.OrchestrationConfigClient; -import com.sap.ai.sdk.prompt.registry.PromptClient; +import com.sap.ai.sdk.prompt.registry.PromptRegistryClient; +import com.sap.ai.sdk.prompt.registry.client.OrchestrationConfigsApi; +import com.sap.ai.sdk.prompt.registry.client.PromptTemplatesApi; import com.sap.ai.sdk.prompt.registry.model.LLMModelDetails; import com.sap.ai.sdk.prompt.registry.model.OrchestrationConfigDeleteResponse; import com.sap.ai.sdk.prompt.registry.model.OrchestrationConfigListResponse; @@ -49,8 +50,9 @@ @RequestMapping("/prompt-registry") class PromptRegistryController { static final String NAME = "java-e2e-test"; - private static final PromptClient promptClient = new PromptClient(); - private static final OrchestrationConfigClient orchConfigClient = new OrchestrationConfigClient(); + private static final OrchestrationConfigsApi orchConfigClient = + new PromptRegistryClient().orchestrationConfig(); + private static final PromptTemplatesApi promptClient = new PromptRegistryClient().prompt(); @GetMapping("/listTemplates") PromptTemplateListResponse listTemplates() { @@ -135,16 +137,15 @@ Generation promptRegistryToSpringAi() { val cl = ChatClient.builder(openAiClient).defaultAdvisors(advisor).build(); val promptResponse = - new PromptClient() - .parsePromptTemplateByNameVersion( - "categorization", - "0.0.1", - "java-e2e-test", - "default", - null, - false, - PromptTemplateSubstitutionRequest.create() - .inputParams(Map.of("inputExample", "I love football"))); + promptClient.parsePromptTemplateByNameVersion( + "categorization", + "0.0.1", + "java-e2e-test", + "default", + null, + false, + PromptTemplateSubstitutionRequest.create() + .inputParams(Map.of("inputExample", "I love football"))); final List messages = SpringAiConverter.promptTemplateToMessages(promptResponse); val prompt = new Prompt(messages); 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 088cfab5f..3f7fbc952 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 @@ -46,7 +46,8 @@ import com.sap.ai.sdk.orchestration.model.SearchDocumentKeyValueListPair; import com.sap.ai.sdk.orchestration.model.SearchSelectOptionEnum; import com.sap.ai.sdk.orchestration.model.Template; -import com.sap.ai.sdk.prompt.registry.OrchestrationConfigClient; +import com.sap.ai.sdk.prompt.registry.PromptRegistryClient; +import com.sap.ai.sdk.prompt.registry.client.OrchestrationConfigsApi; import com.sap.ai.sdk.prompt.registry.model.LLMModelDetails; import com.sap.ai.sdk.prompt.registry.model.OrchestrationConfigPostRequest; import com.sap.ai.sdk.prompt.registry.model.PartialModuleConfigs; @@ -888,7 +889,8 @@ public OrchestrationChatResponse executeConfigFromReference() { } private void ensureOrchestrationConfigExists(final String scenario, final String name) { - final OrchestrationConfigClient orchConfigClient = new OrchestrationConfigClient(); + final OrchestrationConfigsApi orchConfigClient = + new PromptRegistryClient().orchestrationConfig(); if (!orchConfigExists("test-config-for-OrchestrationTest", orchConfigClient)) { final OrchestrationConfigPostRequest postRequest = OrchestrationConfigPostRequest.create() @@ -901,8 +903,8 @@ private void ensureOrchestrationConfigExists(final String scenario, final String } private boolean orchConfigExists( - final String configName, final OrchestrationConfigClient orchConfigClient) { - return orchConfigClient.listOrchestrationConfigs().getResources().stream() + final String configName, final OrchestrationConfigsApi orchestrationConfigsClient) { + return orchestrationConfigsClient.listOrchestrationConfigs().getResources().stream() .anyMatch(resp -> resp.getName().equals(configName)); } @@ -975,7 +977,7 @@ public Stream streamDeltasWithInlineConfig( public Stream streamDeltasWithReferenceById() { // get a valid id ensureOrchestrationConfigExists("sdk-test-paraphrase", "create-3-paraphrases-of-sentence"); - val orchConfigClient = new OrchestrationConfigClient(); + val orchConfigClient = new PromptRegistryClient().orchestrationConfig(); val id = orchConfigClient.listOrchestrationConfigs().getResources().stream() .filter(r -> r.getName().equals("test-config-for-OrchestrationTest"))