Skip to content

Commit e6a8239

Browse files
committed
small changes, more tests, and codestyle etc.
1 parent 7a6d117 commit e6a8239

File tree

11 files changed

+204
-47
lines changed

11 files changed

+204
-47
lines changed

core-services/prompt-registry/pom.xml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@
3838
</scm>
3939
<properties>
4040
<project.rootdir>${project.basedir}/../../</project.rootdir>
41-
<coverage.complexity>73%</coverage.complexity>
42-
<coverage.line>87%</coverage.line>
43-
<coverage.instruction>89%</coverage.instruction>
44-
<coverage.branch>75%</coverage.branch>
45-
<coverage.method>75%</coverage.method>
41+
<coverage.complexity>85%</coverage.complexity>
42+
<coverage.line>91%</coverage.line>
43+
<coverage.instruction>93%</coverage.instruction>
44+
<coverage.branch>100%</coverage.branch>
45+
<coverage.method>81%</coverage.method>
4646
<coverage.class>100%</coverage.class>
4747
</properties>
4848

@@ -101,6 +101,10 @@
101101
<groupId>com.fasterxml.jackson.dataformat</groupId>
102102
<artifactId>jackson-dataformat-yaml</artifactId>
103103
</dependency>
104+
<dependency>
105+
<groupId>com.fasterxml.jackson.core</groupId>
106+
<artifactId>jackson-core</artifactId>
107+
</dependency>
104108
<!-- scope "provided" -->
105109
<dependency>
106110
<groupId>org.projectlombok</groupId>

core-services/prompt-registry/src/main/java/com/sap/ai/sdk/prompt/registry/OrchestrationConfigClient.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.sap.ai.sdk.prompt.registry;
22

3+
import static com.sap.ai.sdk.core.JacksonConfiguration.getDefaultObjectMapper;
4+
35
import com.fasterxml.jackson.annotation.JsonSubTypes;
46
import com.fasterxml.jackson.annotation.JsonTypeInfo;
57
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -23,8 +25,6 @@
2325
import org.springframework.http.converter.yaml.MappingJackson2YamlHttpMessageConverter;
2426
import org.springframework.web.client.RestTemplate;
2527

26-
import static com.sap.ai.sdk.core.JacksonConfiguration.getDefaultObjectMapper;
27-
2828
/**
2929
* Client for managing Orchestration Configurations in the Prompt Registry service.
3030
*
@@ -65,7 +65,7 @@ private static ApiClient addMixin(@Nonnull final AiCoreService service) {
6565
getDefaultObjectMapper()
6666
.addMixIn(OutputFilterConfig.class, JacksonMixin.OutputFilter.class)
6767
.addMixIn(InputFilterConfig.class, JacksonMixin.InputFilter.class)));
68-
var yamlMapper = new ObjectMapper(new YAMLFactory());
68+
final var yamlMapper = new ObjectMapper(new YAMLFactory());
6969
yamlMapper
7070
.addMixIn(OutputFilterConfig.class, JacksonMixin.OutputFilter.class)
7171
.addMixIn(InputFilterConfig.class, JacksonMixin.InputFilter.class);
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.sap.ai.sdk.prompt.registry;
2+
3+
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
4+
import static org.assertj.core.api.Assertions.assertThat;
5+
6+
import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
7+
import com.sap.ai.sdk.core.AiCoreService;
8+
import com.sap.cloud.sdk.cloudplatform.connectivity.DefaultHttpDestination;
9+
import com.sap.cloud.sdk.cloudplatform.connectivity.HttpDestination;
10+
import java.util.UUID;
11+
import org.junit.jupiter.api.BeforeEach;
12+
import org.junit.jupiter.api.Test;
13+
import org.junit.jupiter.api.extension.RegisterExtension;
14+
15+
public class OrchestrationConfigClientTest {
16+
@RegisterExtension
17+
private static final WireMockExtension WM =
18+
WireMockExtension.newInstance().options(wireMockConfig().dynamicPort()).build();
19+
20+
private static OrchestrationConfigClient client;
21+
22+
@BeforeEach
23+
void setup() {
24+
final HttpDestination destination = DefaultHttpDestination.builder(WM.baseUrl()).build();
25+
final AiCoreService service = new AiCoreService().withBaseDestination(destination);
26+
client = new OrchestrationConfigClient(service);
27+
}
28+
29+
@Test
30+
void testPipelines() {
31+
final var result = client.listOrchestrationConfigs();
32+
assertThat(result.getCount()).isEqualTo(2);
33+
assertThat(result.getResources()).hasSize(2);
34+
final var template = result.getResources().get(0);
35+
assertThat(template.getId()).isEqualTo(UUID.fromString("62e8638a-ae87-4bd5-9027-a0bc67db1609"));
36+
assertThat(template.getName()).isEqualTo("test-config-for-OrchestrationTest");
37+
assertThat(template.getVersion()).isEqualTo("0.0.1");
38+
assertThat(template.getScenario()).isEqualTo("sdk-test-scenario");
39+
assertThat(template.getCreationTimestamp()).isEqualTo("2025-12-19T16:24:27.442000");
40+
assertThat(template.getManagedBy()).isEqualTo("imperative");
41+
assertThat(template.isIsVersionHead()).isEqualTo(true);
42+
}
43+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"request": {
3+
"method": "GET",
4+
"url": "/v2/registry/v2/orchestrationConfigs"
5+
},
6+
"response": {
7+
"status": 200,
8+
"headers": {
9+
"Content-Type": "application/json"
10+
},
11+
"jsonBody": {
12+
"count": 2,
13+
"resources": [
14+
{
15+
"id": "62e8638a-ae87-4bd5-9027-a0bc67db1609",
16+
"name": "test-config-for-OrchestrationTest",
17+
"version": "0.0.1",
18+
"scenario": "sdk-test-scenario",
19+
"creation_timestamp": "2025-12-19T16:24:27.442000",
20+
"managed_by": "imperative",
21+
"is_version_head": true
22+
},
23+
{
24+
"id": "f9f2875a-4c92-471b-a403-51a50e70fe52",
25+
"name": "test-config",
26+
"version": "0.0.1",
27+
"scenario": "sdk-test-scenario",
28+
"creation_timestamp": "2025-12-19T16:33:05.607000",
29+
"managed_by": "imperative",
30+
"is_version_head": true
31+
}
32+
]
33+
}
34+
}
35+
}

docs/release_notes.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
### ✨ New Functionality
1414

1515
- [Orchestration] Added new models for `OrchestrationAiModel`: `SONAR`,`SONAR_PRO`, `GEMINI_2_5_FLASH_LITE`, `CLAUDE_4_5_HAIKU`.
16+
- [Orchestration] Configs stored in prompt registry can now be used for Orchestration calls via reference.
1617
- [Orchestration] Convenience for adding the `metadata_params` option to grounding calls.
18+
- [Prompt Registry] Added support to manage Orchestration configs stored in Prompt Registry.
1719

1820
### 📈 Improvements
1921

orchestration/pom.xml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@
3636
</scm>
3737
<properties>
3838
<project.rootdir>${project.basedir}/../</project.rootdir>
39-
<coverage.complexity>80%</coverage.complexity>
40-
<coverage.line>94%</coverage.line>
39+
<coverage.complexity>82%</coverage.complexity>
40+
<coverage.line>95%</coverage.line>
4141
<coverage.instruction>93%</coverage.instruction>
42-
<coverage.branch>74%</coverage.branch>
43-
<coverage.method>93%</coverage.method>
42+
<coverage.branch>75%</coverage.branch>
43+
<coverage.method>94%</coverage.method>
4444
<coverage.class>100%</coverage.class>
4545
</properties>
4646

orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationClient.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import java.util.stream.Stream;
2727
import javax.annotation.Nonnull;
2828
import javax.annotation.Nullable;
29-
3029
import lombok.RequiredArgsConstructor;
3130
import lombok.extern.slf4j.Slf4j;
3231
import lombok.val;
@@ -168,12 +167,22 @@ public CompletionPostResponse executeRequest(@Nonnull final CompletionPostReques
168167
COMPLETION_ENDPOINT, request, CompletionPostResponse.class, customHeaders);
169168
}
170169

170+
/**
171+
* Generate a completion using a referenced Orchestration config and a prompt.
172+
*
173+
* @param prompt The prompt to store placeholder values and the message history
174+
* @param reference A reference to an Orchestration config stored in prompt registry
175+
* @return The completion output
176+
* @since 1.14.0
177+
*/
171178
@Beta
179+
@Nonnull
172180
public OrchestrationChatResponse executeRequestFromReference(
173-
@Nullable final OrchestrationPrompt prompt, @Nonnull final OrchestrationConfigReference reference) {
174-
var request =
181+
@Nullable final OrchestrationPrompt prompt,
182+
@Nonnull final OrchestrationConfigReference reference) {
183+
val request =
175184
ConfigToRequestTransformer.fromReferenceToCompletionPostRequest(prompt, reference);
176-
var response = executeRequest(request);
185+
val response = executeRequest(request);
177186
return new OrchestrationChatResponse(response);
178187
}
179188

orchestration/src/main/java/com/sap/ai/sdk/orchestration/OrchestrationConfigReference.java

Lines changed: 69 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,14 @@
44
import javax.annotation.Nonnull;
55
import lombok.AccessLevel;
66
import lombok.AllArgsConstructor;
7+
import lombok.RequiredArgsConstructor;
78
import lombok.Value;
89

9-
// JONAS: Making this a sealed interface permitting 2 classes for ID and SNV seemed like an overkill
10-
// JONAS: Not a record because I do not want a public all-args constructor
11-
// JONAS: Is string correct for ID? (Use UUID?)
12-
// JONAS: Split SNV into 3 methods?
13-
10+
/**
11+
* Class representing a reference to an Orchestration config stored in prompt registry.
12+
*
13+
* @since 1.14.0
14+
*/
1415
@Value
1516
@AllArgsConstructor(access = AccessLevel.PRIVATE)
1617
@Beta
@@ -20,12 +21,72 @@ public class OrchestrationConfigReference {
2021
String name;
2122
String version;
2223

24+
/**
25+
* Build a reference from an ID.
26+
*
27+
* @param id The id of the reference
28+
* @return A reference object with the specified id
29+
* @since 1.14.0
30+
*/
31+
@Nonnull
2332
public static OrchestrationConfigReference fromId(@Nonnull final String id) {
2433
return new OrchestrationConfigReference(id, null, null, null);
2534
}
2635

27-
public static OrchestrationConfigReference fromScenarioNameVersion(
28-
@Nonnull final String scenario, @Nonnull final String name, @Nonnull final String version) {
29-
return new OrchestrationConfigReference(null, scenario, name, version);
36+
/**
37+
* Build a reference from a scenario, name, and version.
38+
*
39+
* @param scenario The scenario of the reference
40+
* @return A builder object with the specified scenario
41+
* @since 1.14.0
42+
*/
43+
@Nonnull
44+
public static Builder fromScenario(@Nonnull final String scenario) {
45+
return new Builder(scenario);
46+
}
47+
48+
/**
49+
* Builder to create an Orchestration config reference from scenario, name, and version.
50+
*
51+
* @since 1.14.0
52+
*/
53+
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
54+
public static class Builder {
55+
private final String scenario;
56+
57+
/**
58+
* Build a reference from a scenario, name, and version.
59+
*
60+
* @param name The name of the reference
61+
* @return A builder object with the specified scenario and name
62+
* @since 1.14.0
63+
*/
64+
@Nonnull
65+
public Builder1 name(@Nonnull final String name) {
66+
return new Builder1(scenario, name);
67+
}
68+
}
69+
70+
/**
71+
* Builder to create an Orchestration config reference from scenario, name, and version.
72+
*
73+
* @since 1.14.0
74+
*/
75+
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
76+
public static class Builder1 {
77+
private final String scenario;
78+
private final String name;
79+
80+
/**
81+
* Build a reference from a scenario, name, and version.
82+
*
83+
* @param version The version of the reference
84+
* @return A reference object with the specified scenario, name, and version
85+
* @since 1.14.0
86+
*/
87+
@Nonnull
88+
public OrchestrationConfigReference version(@Nonnull final String version) {
89+
return new OrchestrationConfigReference(null, scenario, name, version);
90+
}
3091
}
3192
}

orchestration/src/test/java/com/sap/ai/sdk/orchestration/OrchestrationUnitTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,7 +1373,7 @@ void testExecuteFromReferenceBySNV() {
13731373
.withHeader("Content-Type", "application/json")));
13741374

13751375
var reference =
1376-
OrchestrationConfigReference.fromScenarioNameVersion("scenario", "name", "0.0.1");
1376+
OrchestrationConfigReference.fromScenario("scenario").name("name").version("0.0.1");
13771377
final var response = client.executeRequestFromReference(null, reference);
13781378

13791379
final String expectedRequest = fileLoaderStr.apply("orchConfigBySNVRequest.json");
@@ -1390,7 +1390,7 @@ void testExecuteFromReferenceWithMessageHistoryAndInputParams() {
13901390
.withHeader("Content-Type", "application/json")));
13911391

13921392
var reference =
1393-
OrchestrationConfigReference.fromScenarioNameVersion("scenario", "name", "0.0.1");
1393+
OrchestrationConfigReference.fromScenario("scenario").name("name").version("0.0.1");
13941394
List<Message> history = List.of(new SystemMessage("System Message"));
13951395
var prompt = new OrchestrationPrompt(Map.of("placeholder", "value")).messageHistory(history);
13961396
final var response = client.executeRequestFromReference(prompt, reference);

sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/PromptRegistryController.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
import com.sap.ai.sdk.foundationmodels.openai.spring.OpenAiChatModel;
66
import com.sap.ai.sdk.prompt.registry.OrchestrationConfigClient;
77
import com.sap.ai.sdk.prompt.registry.PromptClient;
8-
import com.sap.ai.sdk.prompt.registry.model.ChatMessage;
9-
import com.sap.ai.sdk.prompt.registry.model.ChatMessageContent;
108
import com.sap.ai.sdk.prompt.registry.model.LLMModelDetails;
119
import com.sap.ai.sdk.prompt.registry.model.ModuleConfigs;
1210
import com.sap.ai.sdk.prompt.registry.model.OrchestrationConfig;
@@ -22,9 +20,7 @@
2220
import com.sap.ai.sdk.prompt.registry.model.PromptTemplateSubstitutionRequest;
2321
import com.sap.ai.sdk.prompt.registry.model.PromptTemplateSubstitutionResponse;
2422
import com.sap.ai.sdk.prompt.registry.model.PromptTemplatingModuleConfig;
25-
import com.sap.ai.sdk.prompt.registry.model.PromptTemplatingModuleConfigPrompt;
2623
import com.sap.ai.sdk.prompt.registry.model.SingleChatTemplate;
27-
import com.sap.ai.sdk.prompt.registry.model.SystemChatMessage;
2824
import com.sap.ai.sdk.prompt.registry.model.Template;
2925
import com.sap.ai.sdk.prompt.registry.model.UserChatMessage;
3026
import com.sap.ai.sdk.prompt.registry.model.UserChatMessageContent;
@@ -163,7 +159,7 @@ OrchestrationConfigListResponse listOrchConfigs() {
163159

164160
@GetMapping("/createOrchConfig")
165161
OrchestrationConfigPostResponse createOrchConfig() {
166-
OrchestrationConfigPostRequest postRequest =
162+
final OrchestrationConfigPostRequest postRequest =
167163
OrchestrationConfigPostRequest.create()
168164
.name(NAME)
169165
.version("0.0.1")

0 commit comments

Comments
 (0)