-
Notifications
You must be signed in to change notification settings - Fork 22
refactor: use single factory instead of inheritance for prompt registry clients #1046
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v2
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 orchestration() { | ||
| return new OrchestrationConfigsApi(OrchestrationConfigMixin.addMixin(aiCoreService)); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,18 +17,18 @@ public class OrchestrationConfigClientTest { | |
| private static final WireMockExtension WM = | ||
| WireMockExtension.newInstance().options(wireMockConfig().dynamicPort()).build(); | ||
|
|
||
| private static OrchestrationConfigClient client; | ||
| private static PromptRegistryClient client; | ||
|
|
||
| @BeforeEach | ||
| void setup() { | ||
| final HttpDestination destination = DefaultHttpDestination.builder(WM.baseUrl()).build(); | ||
| final AiCoreService service = new AiCoreService().withBaseDestination(destination); | ||
| client = new OrchestrationConfigClient(service); | ||
| client = new PromptRegistryClient(service); | ||
| } | ||
|
|
||
| @Test | ||
| void testPipelines() { | ||
| final var result = client.listOrchestrationConfigs(); | ||
| final var result = client.orchestration().listOrchestrationConfigs(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here |
||
| assertThat(result.getCount()).isEqualTo(2); | ||
| assertThat(result.getResources()).hasSize(2); | ||
| final var template = result.getResources().get(0); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ | |
|
|
||
| import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; | ||
| import static org.assertj.core.api.Assertions.assertThat; | ||
| import static org.assertj.core.api.Assertions.assertThatCode; | ||
| import static org.assertj.core.api.Assertions.assertThatThrownBy; | ||
|
|
||
| import com.github.tomakehurst.wiremock.junit5.WireMockExtension; | ||
|
|
@@ -14,10 +15,16 @@ | |
| import com.sap.ai.sdk.prompt.registry.model.ResponseFormatText; | ||
| import com.sap.ai.sdk.prompt.registry.model.SingleChatTemplate; | ||
| import com.sap.ai.sdk.prompt.registry.model.TextContent; | ||
| import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; | ||
| import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingBuilder; | ||
| import com.sap.cloud.environment.servicebinding.api.ServiceBindingAccessor; | ||
| import com.sap.cloud.environment.servicebinding.api.ServiceIdentifier; | ||
| 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 java.util.UUID; | ||
| import org.junit.jupiter.api.AfterEach; | ||
| import org.junit.jupiter.api.BeforeEach; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.junit.jupiter.api.extension.RegisterExtension; | ||
|
|
@@ -27,18 +34,43 @@ class PromptRegistryClientTest { | |
| private static final WireMockExtension WM = | ||
| WireMockExtension.newInstance().options(wireMockConfig().dynamicPort()).build(); | ||
|
|
||
| private static PromptClient client; | ||
| private static PromptRegistryClient client; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could store the multiple clients here instead, like in |
||
| private ServiceBindingAccessor originalAccessor; | ||
|
|
||
| @BeforeEach | ||
| void setup() { | ||
| originalAccessor = DefaultServiceBindingAccessor.getInstance(); | ||
| final HttpDestination destination = DefaultHttpDestination.builder(WM.baseUrl()).build(); | ||
| final AiCoreService service = new AiCoreService().withBaseDestination(destination); | ||
| client = new PromptClient(service); | ||
| client = new PromptRegistryClient(service); | ||
| } | ||
|
|
||
| @AfterEach | ||
| void teardown() { | ||
| DefaultServiceBindingAccessor.setInstance(originalAccessor); | ||
| } | ||
|
|
||
| @Test | ||
| void testDefaultConstructor() { | ||
| final var binding = | ||
| new DefaultServiceBindingBuilder() | ||
| .withServiceIdentifier(ServiceIdentifier.AI_CORE) | ||
| .withCredentials( | ||
| Map.of( | ||
| "clientid", "client-id", | ||
| "clientsecret", "client-secret", | ||
| "credential-type", "binding-secret", | ||
| "url", WM.baseUrl(), | ||
| "serviceurls", Map.of("AI_API_URL", WM.baseUrl()))) | ||
| .build(); | ||
| DefaultServiceBindingAccessor.setInstance(() -> List.of(binding)); | ||
|
|
||
| assertThatCode(PromptRegistryClient::new).doesNotThrowAnyException(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are you testing the AiCoreService default constructor behaviour? |
||
| } | ||
|
|
||
| @Test | ||
| void testPipelines() { | ||
| final var result = client.listPromptTemplates(); | ||
| final var result = client.prompt().listPromptTemplates(); | ||
| assertThat(result.getCount()).isEqualTo(2); | ||
| assertThat(result.getResources()).hasSize(2); | ||
| final var template = result.getResources().get(0); | ||
|
|
@@ -55,7 +87,7 @@ void testPipelines() { | |
| @Test | ||
| void testGetTemplateWithResponseFormatText() { | ||
| final var uuid = UUID.fromString("22117a64-9f2c-481b-9402-8acb66eeb707"); | ||
| final PromptTemplateGetResponse response = client.getPromptTemplateByUuid(uuid); | ||
| final PromptTemplateGetResponse response = client.prompt().getPromptTemplateByUuid(uuid); | ||
|
|
||
| assertThat(response.getName()).isEqualTo("test"); | ||
| assertThat(response.getVersion()).isEqualTo("0.0.1"); | ||
|
|
@@ -70,7 +102,7 @@ void testGetTemplateWithResponseFormatText() { | |
| @Test | ||
| void testGetTemplateWithResponseFormatJsonObject() { | ||
| final var uuid = UUID.fromString("21cb1358-0bf1-4f43-870b-00f14d0f9f16"); | ||
| final var response = client.getPromptTemplateByUuid(uuid); | ||
| final var response = client.prompt().getPromptTemplateByUuid(uuid); | ||
|
|
||
| assertThat(response.getName()).isEqualTo("test"); | ||
| assertThat(response.getVersion()).isEqualTo("0.0.1"); | ||
|
|
@@ -85,7 +117,7 @@ void testGetTemplateWithResponseFormatJsonObject() { | |
| @Test | ||
| void testGetTemplateWithResponseFormatJsonSchema() { | ||
| final var uuid = UUID.fromString("0f79fec4-ae07-4c35-96e3-df7f4a3f1df5"); | ||
| final var response = client.getPromptTemplateByUuid(uuid); | ||
| final var response = client.prompt().getPromptTemplateByUuid(uuid); | ||
|
|
||
| assertThat(response.getName()).isEqualTo("test"); | ||
| assertThat(response.getVersion()).isEqualTo("0.0.1"); | ||
|
|
@@ -105,7 +137,7 @@ void testGetTemplateWithResponseFormatJsonSchema() { | |
| @Test | ||
| void testGetTemplateWithMultiChatTemplate() { | ||
| final var uuid = UUID.fromString("8f79fec4-ae07-4c35-96e3-df7f4a3f1df5"); | ||
| final var response = client.getPromptTemplateByUuid(uuid); | ||
| final var response = client.prompt().getPromptTemplateByUuid(uuid); | ||
|
|
||
| assertThat(response.getSpec()).isNotNull(); | ||
| assertThat(response.getSpec().getTemplate()).hasSize(2); | ||
|
|
@@ -126,15 +158,15 @@ void testGetTemplateWithMultiChatTemplate() { | |
| void testGetTemplateWithInvalidRoleType() { | ||
| final var uuid = UUID.fromString("45cb1358-0bf1-4f43-870b-00f14d0f9f16"); | ||
|
|
||
| assertThatThrownBy(() -> client.getPromptTemplateByUuid(uuid)) | ||
| assertThatThrownBy(() -> client.prompt().getPromptTemplateByUuid(uuid)) | ||
| .hasStackTraceContaining("PromptTemplate requires textual 'role' property."); | ||
| } | ||
|
|
||
| @Test | ||
| void testGetTemplateWithInvalidContentType() { | ||
| final var uuid = UUID.fromString("55cb1358-0bf1-4f43-870b-00f14d0f9f16"); | ||
|
|
||
| assertThatThrownBy(() -> client.getPromptTemplateByUuid(uuid)) | ||
| assertThatThrownBy(() -> client.prompt().getPromptTemplateByUuid(uuid)) | ||
| .hasStackTraceContaining( | ||
| "PromptTemplate content must be either a string or an array, but found: BOOLEAN"); | ||
| } | ||
|
|
@@ -146,8 +178,10 @@ void testParsePromptTemplateHotPath() { | |
| .inputParams(Map.of("inputExample", "I love football")); | ||
|
|
||
| final var response = | ||
| client.parsePromptTemplateByNameVersion( | ||
| "categorization", "0.0.1", "hotpath-serde", "default", null, false, request); | ||
| client | ||
| .prompt() | ||
| .parsePromptTemplateByNameVersion( | ||
| "categorization", "0.0.1", "hotpath-serde", "default", null, false, request); | ||
|
|
||
| assertThat(response.getParsedPrompt()).hasSize(2); | ||
| assertThat(response.getParsedPrompt().get(0)).isInstanceOf(SingleChatTemplate.class); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.