Skip to content

Commit f42a8c0

Browse files
committed
Merge remote-tracking branch 'origin/main' into openai/generated-model
2 parents 72a9f8f + 62faaab commit f42a8c0

File tree

103 files changed

+940
-144
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+940
-144
lines changed

docs/guides/ORCHESTRATION_CHAT_COMPLETION.md

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ Use a prepared template and execute requests with by passing only the input para
108108

109109
```java
110110
var template = Message.user("Reply with 'Orchestration Service is working!' in {{?language}}");
111-
var templatingConfig = TemplatingModuleConfig.create().template(template);
111+
var templatingConfig =
112+
TemplateConfig.create().withTemplate(List.of(template.createChatMessage()));
112113
var configWithTemplate = config.withTemplateConfig(templatingConfig);
113114

114115
var inputParams = Map.of("language", "German");
@@ -119,6 +120,22 @@ var result = client.chatCompletion(prompt, configWithTemplate);
119120

120121
In this case the template is defined with the placeholder `{{?language}}` which is replaced by the value `German` in the input parameters.
121122

123+
Alternatively, you can use already prepared templates from the [Prompt Registry](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/prompt-registry) of SAP AI Core instead of passing a template in the request yourself.
124+
125+
```java
126+
var template = TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16");
127+
var configWithTemplate = config.withTemplateConfig(template);
128+
129+
var inputParams = Map.of("language", "Italian", "input", "cloud ERP systems");
130+
var prompt = new OrchestrationPrompt(inputParams);
131+
132+
var result = client.chatCompletion(prompt, configWithTemplate);
133+
```
134+
135+
A prompt template can be referenced either by ID as above, or by using a combination of name, scenario, and version. For details on storing a template in the Prompt Registry, refer to [this guide](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/create-prompt-template-imperative).
136+
137+
You can find [some examples](https://github.com/SAP/ai-sdk-java/tree/main/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java) in our Spring Boot application demonstrating using templates from Prompt Registry.
138+
122139
## Message history
123140

124141
Include a message history to maintain context in the conversation:
@@ -210,6 +227,10 @@ In this example, the input will be masked before the call to the LLM and will re
210227

211228
Use the grounding module to provide additional context to the AI model.
212229

230+
### Vector Data Repository
231+
232+
One way to provide grounding is by using a vector data repository. This can be done as follows.
233+
213234
```java
214235
// optional filter for collections
215236
var documentMetadata =
@@ -233,7 +254,37 @@ var result = client.chatCompletion(prompt, configWithGrounding);
233254

234255
In this example, the AI model is provided with additional context in the form of grounding information.
235256

236-
`Grounding.create()` is by default a document grounding service with a vector data repository.
257+
### Grounding via *help.sap.com*
258+
259+
You can also use grounding based on *help.sap.com* for convenient SAP specific grounding. This can be achieved as follows.
260+
261+
```java
262+
var groundingHelpSapCom =
263+
DocumentGroundingFilter.create()
264+
.dataRepositoryType(DataRepositoryType.HELP_SAP_COM);
265+
var groundingConfig = Grounding.create().filters(groundingHelpSapCom);
266+
var configWithGrounding = config.withGrounding(groundingConfig);
267+
268+
var prompt = groundingConfig.createGroundingPrompt("What is a fuzzy search?");
269+
var response = client.chatCompletion(prompt, configWithGrounding);
270+
```
271+
272+
Please find [an example in our Spring Boot application](../../sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java).
273+
274+
### Mask Grounding
275+
276+
You can also mask both the grounding information and the prompt message:
277+
278+
```java
279+
var maskingConfig =
280+
DpiMasking.anonymization()
281+
.withEntities(DPIEntities.SENSITIVE_DATA)
282+
.withMaskGroundingEnabled()
283+
.withAllowList(List.of("SAP", "Joule"));
284+
var maskedGroundingConfig = groundingConfig.withMaskingConfig(maskingConfig);
285+
286+
var result = client.chatCompletion(prompt, maskedGroundingConfig);
287+
```
237288

238289
Please find [an example in our Spring Boot application](../../sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OrchestrationService.java).
239290

docs/guides/SPRING_AI_INTEGRATION.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- [Orchestration Masking](#orchestration-masking)
88
- [Stream chat completion](#stream-chat-completion)
99
- [Tool Calling](#tool-calling)
10+
- [Chat Memory](#chat-memory)
1011

1112
## Introduction
1213

@@ -137,3 +138,26 @@ ChatResponse response = client.call(prompt);
137138

138139
Please find [an example in our Spring Boot application](../../sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/SpringAiOrchestrationService.java).
139140

141+
## Chat Memory
142+
143+
Create a Spring AI `ChatClient` from our `OrchestrationChatModel` and add a chat memory advisor like so:
144+
145+
```java
146+
ChatModel client = new OrchestrationChatModel();
147+
OrchestrationModuleConfig config = new OrchestrationModuleConfig().withLlmConfig(GPT_35_TURBO);
148+
OrchestrationChatOptions opts = new OrchestrationChatOptions(config);
149+
150+
val memory = new InMemoryChatMemory();
151+
val advisor = new MessageChatMemoryAdvisor(memory);
152+
val cl = ChatClient.builder(client).defaultAdvisors(advisor).build();
153+
154+
Prompt prompt1 = new Prompt("What is the capital of France?", defaultOptions);
155+
String content1 = cl.prompt(prompt1).call().content();
156+
// content1 is "Paris"
157+
158+
Prompt prompt2 = new Prompt("And what is the typical food there?", defaultOptions);
159+
String content2 = cl.prompt(prompt2).call().content();
160+
// chat memory will remember that the user is inquiring about France.
161+
```
162+
163+
Please find [an example in our Spring Boot application](../../sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/SpringAiOrchestrationService.java).

docs/release-notes/release_notes.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212

1313
### ✨ New Functionality
1414

15-
-
15+
- [Orchestration] [Add Spring AI Chat Memory support](https://github.com/SAP/ai-sdk-java/tree/main/docs/guides/SPRING_AI_INTEGRATION.md#chat-memory)
16+
- [Orchestration] [Prompt templates can be consumed from registry.](https://github.com/SAP/ai-sdk-java/tree/main/docs/guides/ORCHESTRATION_CHAT_COMPLETION.md#Chat-completion-with-Templates)
17+
- [Orchestration] [Masking is now available on grounding.](https://github.com/SAP/ai-sdk-java/tree/main/docs/guides/ORCHESTRATION_CHAT_COMPLETION.md#mask-grounding)
18+
- [Orchestration] [Grounding via *help.sap.com* is enabled.](https://github.com/SAP/ai-sdk-java/tree/main/docs/guides/ORCHESTRATION_CHAT_COMPLETION.md#grounding)
1619

1720
### 📈 Improvements
1821

foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiError.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import lombok.AccessLevel;
99
import lombok.AllArgsConstructor;
1010
import lombok.Value;
11-
import lombok.experimental.Delegate;
1211

1312
/**
1413
* Represents an error response from the OpenAI API.
@@ -20,7 +19,6 @@
2019
@AllArgsConstructor(onConstructor = @__({@JsonCreator}), access = AccessLevel.PROTECTED)
2120
public class OpenAiError implements ClientError {
2221
/** The original error response from the OpenAI API. */
23-
@Delegate(types = {ClientError.class})
2422
ErrorResponse originalResponse;
2523

2624
/**

orchestration/pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@
3131
</developers>
3232
<properties>
3333
<project.rootdir>${project.basedir}/../</project.rootdir>
34-
<coverage.complexity>82%</coverage.complexity>
35-
<coverage.line>93%</coverage.line>
34+
<coverage.complexity>83%</coverage.complexity>
35+
<coverage.line>94%</coverage.line>
3636
<coverage.instruction>94%</coverage.instruction>
37-
<coverage.branch>76%</coverage.branch>
37+
<coverage.branch>77%</coverage.branch>
3838
<coverage.method>93%</coverage.method>
3939
<coverage.class>100%</coverage.class>
4040
</properties>

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.sap.ai.sdk.orchestration.model.ModuleConfigs;
66
import com.sap.ai.sdk.orchestration.model.OrchestrationConfig;
77
import com.sap.ai.sdk.orchestration.model.Template;
8+
import com.sap.ai.sdk.orchestration.model.TemplateRef;
89
import com.sap.ai.sdk.orchestration.model.TemplatingModuleConfig;
910
import io.vavr.control.Option;
1011
import java.util.ArrayList;
@@ -47,6 +48,9 @@ static TemplatingModuleConfig toTemplateModuleConfig(
4748
* In this case, the request will fail, since the templating module will try to resolve the parameter.
4849
* To be fixed with https://github.tools.sap/AI/llm-orchestration/issues/662
4950
*/
51+
if (config instanceof TemplateRef) {
52+
return config;
53+
}
5054
val template = config instanceof Template t ? t : Template.create().template();
5155
val messages = template.getTemplate();
5256
val responseFormat = template.getResponseFormat();

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

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import static com.sap.ai.sdk.orchestration.model.DPIConfig.TypeEnum.SAP_DATA_PRIVACY_INTEGRATION;
66

77
import com.sap.ai.sdk.orchestration.model.DPIConfig;
8+
import com.sap.ai.sdk.orchestration.model.DPIConfigMaskGroundingInput;
89
import com.sap.ai.sdk.orchestration.model.DPIEntities;
910
import com.sap.ai.sdk.orchestration.model.DPIEntityConfig;
1011
import com.sap.ai.sdk.orchestration.model.MaskingProviderConfig;
@@ -16,6 +17,7 @@
1617
import lombok.Getter;
1718
import lombok.RequiredArgsConstructor;
1819
import lombok.Value;
20+
import lombok.With;
1921
import lombok.val;
2022

2123
/**
@@ -31,6 +33,8 @@
3133
public class DpiMasking implements MaskingProvider {
3234
@Nonnull DPIConfig.MethodEnum maskingMethod;
3335
@Nonnull List<DPIEntities> entities;
36+
@With boolean maskGroundingInput;
37+
@Nonnull List<String> allowList;
3438

3539
/**
3640
* Build a configuration applying anonymization.
@@ -65,7 +69,7 @@ public static class Builder {
6569
*
6670
* @param entity An entity type to mask (required)
6771
* @param entities Additional entity types to mask (optional)
68-
* @return A configured {@link DpiMasking} instance
72+
* @return A new {@link DpiMasking} instance
6973
* @see DPIEntities
7074
*/
7175
@Nonnull
@@ -74,17 +78,30 @@ public DpiMasking withEntities(
7478
val entitiesList = new ArrayList<DPIEntities>();
7579
entitiesList.add(entity);
7680
entitiesList.addAll(Arrays.asList(entities));
77-
return new DpiMasking(maskingMethod, entitiesList);
81+
return new DpiMasking(maskingMethod, entitiesList, false, List.of());
7882
}
7983
}
8084

85+
/**
86+
* Set words that should not be masked.
87+
*
88+
* @param allowList List of strings that should not be masked
89+
* @return A new {@link DpiMasking} instance
90+
*/
91+
@Nonnull
92+
public DpiMasking withAllowList(@Nonnull final List<String> allowList) {
93+
return new DpiMasking(maskingMethod, entities, maskGroundingInput, allowList);
94+
}
95+
8196
@Nonnull
8297
@Override
8398
public MaskingProviderConfig createConfig() {
8499
val entitiesDTO = entities.stream().map(it -> DPIEntityConfig.create().type(it)).toList();
85100
return DPIConfig.create()
86101
.type(SAP_DATA_PRIVACY_INTEGRATION)
87102
.method(maskingMethod)
88-
.entities(entitiesDTO);
103+
.entities(entitiesDTO)
104+
.maskGroundingInput(DPIConfigMaskGroundingInput.create().enabled(maskGroundingInput))
105+
.allowlist(allowList);
89106
}
90107
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ public GroundingModuleConfig createConfig() {
8585
.outputParam("groundingContext")
8686
.filters(filters);
8787

88+
if (filters.contains(
89+
DocumentGroundingFilter.create().dataRepositoryType(DataRepositoryType.HELP_SAP_COM))) {
90+
groundingConfigConfig.setMetadataParams(null);
91+
}
92+
8893
return GroundingModuleConfig.create()
8994
.type(documentGroundingService)
9095
.config(groundingConfigConfig);

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
import com.google.common.annotations.Beta;
55
import com.sap.ai.sdk.core.common.ClientError;
66
import com.sap.ai.sdk.orchestration.model.ErrorResponse;
7+
import javax.annotation.Nonnull;
78
import lombok.AccessLevel;
89
import lombok.AllArgsConstructor;
910
import lombok.Value;
10-
import lombok.experimental.Delegate;
1111

1212
/**
1313
* Orchestration error response.
@@ -18,6 +18,17 @@
1818
@Value
1919
@Beta
2020
public class OrchestrationError implements ClientError {
21-
@Delegate(types = {ClientError.class})
2221
ErrorResponse originalResponse;
22+
23+
/**
24+
* Gets the error message from the contained original response.
25+
*
26+
* @return the error message
27+
*/
28+
@Nonnull
29+
public String getMessage() {
30+
return originalResponse.getCode() == 500
31+
? originalResponse.getMessage() + " located in " + originalResponse.getLocation()
32+
: originalResponse.getMessage();
33+
}
2334
}

orchestration/src/main/java/com/sap/ai/sdk/orchestration/model/AzureContentSafety.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* Internal Orchestration Service API
3-
* SAP AI Core - Orchestration Service API
3+
* Orchestration is an inference service which provides common additional capabilities for business AI scenarios, such as content filtering and data masking. At the core of the service is the LLM module which allows for an easy, harmonized access to the language models of gen AI hub. The service is designed to be modular and extensible, allowing for the addition of new modules in the future. Each module can be configured independently and at runtime, allowing for a high degree of flexibility in the orchestration of AI services.
44
*
55
*
66
*

0 commit comments

Comments
 (0)