Skip to content

Commit 1984340

Browse files
CharlesDuboisSAPJonas-Isrbot-sdk-js
authored
fix: [Orchestration] Template Chat Message Type (#449)
* fix: [Orchestration] Template Chat Message Type * Fix .createChatMessage() * better deprecation * green * release notes * Formatting * release notes * review --------- Co-authored-by: Jonas Israel <[email protected]> Co-authored-by: SAP Cloud SDK Bot <[email protected]>
1 parent 97602b0 commit 1984340

22 files changed

+101
-125
lines changed

docs/release_notes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
Interfaces with only one implementation were reduced.
1919
As a result, the accessors for fields `OrchestrationModuleConfig.inputTranslationConfig` and `OrchestrationModuleConfig.outputTranslationConfig` now handle the implementing class explicitly.
2020
The same applies to helper methods `DpiMasking#createConfig()` and `MaskingProvider#createConfig()`.
21+
- [Orchestration] `OrchestrationTemplate.withTemplate()` has been deprecated. Please use `OrchestrationTemplate.withTemplateMessages()` instead.
2122

2223
### ✨ New Functionality
2324

orchestration/pom.xml

Lines changed: 2 additions & 2 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>84%</coverage.complexity>
34+
<coverage.complexity>83%</coverage.complexity>
3535
<coverage.line>94%</coverage.line>
3636
<coverage.instruction>95%</coverage.instruction>
37-
<coverage.branch>79%</coverage.branch>
37+
<coverage.branch>78%</coverage.branch>
3838
<coverage.method>94%</coverage.method>
3939
<coverage.class>100%</coverage.class>
4040
</properties>

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,14 @@ public AssistantMessage(@Nonnull final List<MessageToolCall> toolCalls) {
6666
@Nonnull
6767
@Override
6868
public ChatMessage createChatMessage() {
69-
if (toolCalls() != null) {
69+
if (toolCalls != null) {
7070
return AssistantChatMessage.create().role(ASSISTANT).toolCalls(toolCalls);
7171
}
72+
if (content.items().size() == 1 && content.items().get(0) instanceof TextItem textItem) {
73+
return AssistantChatMessage.create()
74+
.role(ASSISTANT)
75+
.content(ChatMessageContent.create(textItem.text()));
76+
}
7277
val texts =
7378
content.items().stream()
7479
.filter(item -> item instanceof TextItem)

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.HashMap;
2020
import java.util.List;
2121
import java.util.Map;
22+
import java.util.stream.Stream;
2223
import javax.annotation.Nonnull;
2324
import javax.annotation.Nullable;
2425
import lombok.AccessLevel;
@@ -41,8 +42,11 @@
4142
@NoArgsConstructor(force = true, access = AccessLevel.PACKAGE)
4243
@Beta
4344
public class OrchestrationTemplate extends TemplateConfig {
45+
46+
/** Please use {@link #withMessages(Message...)} instead. */
4447
@JsonProperty("template")
4548
@Nullable
49+
@With(onMethod_ = {@Deprecated})
4650
List<ChatMessage> template;
4751

4852
@JsonProperty("defaults")
@@ -58,6 +62,17 @@ public class OrchestrationTemplate extends TemplateConfig {
5862
@Nullable
5963
List<ChatCompletionTool> tools;
6064

65+
/**
66+
* Create a new template with the given messages.
67+
*
68+
* @param messages The messages to use in the template.
69+
* @return The updated template.
70+
*/
71+
@Nonnull
72+
public OrchestrationTemplate withMessages(@Nonnull final Message... messages) {
73+
return this.withTemplate(Stream.of(messages).map(Message::createChatMessage).toList());
74+
}
75+
6176
/**
6277
* Create a low-level representation of the template.
6378
*

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ public SystemMessage withText(@Nonnull final String message) {
5959
@Nonnull
6060
@Override
6161
public ChatMessage createChatMessage() {
62+
if (content.items().size() == 1 && content.items().get(0) instanceof TextItem textItem) {
63+
return SystemChatMessage.create()
64+
.role(SYSTEM)
65+
.content(ChatMessageContent.create(textItem.text()));
66+
}
6267
val texts =
6368
content.items().stream()
6469
.filter(item -> item instanceof TextItem)

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,12 @@ public UserMessage withImage(@Nonnull final String imageUrl) {
9393
public ChatMessage createChatMessage() {
9494
final var contentList = new LinkedList<UserChatMessageContentItem>();
9595

96-
for (final ContentItem item : this.content().items()) {
96+
if (content.items().size() == 1 && content.items().get(0) instanceof TextItem textItem) {
97+
return UserChatMessage.create()
98+
.content(UserChatMessageContent.create(textItem.text()))
99+
.role(USER);
100+
}
101+
for (final ContentItem item : content.items()) {
97102
if (item instanceof TextItem textItem) {
98103
contentList.add(UserChatMessageContentItem.create().type(TEXT).text(textItem.text()));
99104
} else if (item instanceof ImageItem imageItem) {

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

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44
import static org.assertj.core.api.Assertions.assertThat;
55

66
import com.fasterxml.jackson.annotation.JsonProperty;
7+
import com.fasterxml.jackson.databind.JsonNode;
8+
import com.fasterxml.jackson.databind.ObjectMapper;
79
import com.sap.ai.sdk.orchestration.model.ChatCompletionTool;
810
import com.sap.ai.sdk.orchestration.model.ChatMessage;
9-
import com.sap.ai.sdk.orchestration.model.ChatMessageContent;
1011
import com.sap.ai.sdk.orchestration.model.FunctionObject;
1112
import com.sap.ai.sdk.orchestration.model.ResponseFormatJsonObject;
1213
import com.sap.ai.sdk.orchestration.model.ResponseFormatJsonSchema;
1314
import com.sap.ai.sdk.orchestration.model.ResponseFormatJsonSchemaJsonSchema;
14-
import com.sap.ai.sdk.orchestration.model.SystemChatMessage;
15-
import com.sap.ai.sdk.orchestration.model.SystemChatMessage.RoleEnum;
1615
import com.sap.ai.sdk.orchestration.model.Template;
1716
import com.sap.ai.sdk.orchestration.model.TemplateRef;
1817
import com.sap.ai.sdk.orchestration.model.TemplateRefByID;
@@ -129,7 +128,8 @@ void testConfigWithResponseSchema() {
129128

130129
@Test
131130
void testTemplateConstruction() {
132-
List<ChatMessage> templateMessages =
131+
Message templateMessages = Message.user("message");
132+
List<ChatMessage> templateMessagesLowLevel =
133133
List.of(
134134
UserChatMessage.create().content(UserChatMessageContent.create("message")).role(USER));
135135
var defaults = Map.of("key", "value");
@@ -140,14 +140,14 @@ void testTemplateConstruction() {
140140
.function(FunctionObject.create().name("func")));
141141
var template =
142142
TemplateConfig.create()
143-
.withTemplate(templateMessages)
143+
.withMessages(templateMessages)
144144
.withDefaults(defaults)
145145
.withTools(tools)
146146
.withJsonResponse();
147147

148148
var templateLowLevel =
149149
Template.create()
150-
.template(templateMessages)
150+
.template(templateMessagesLowLevel)
151151
.defaults(defaults)
152152
.responseFormat(
153153
ResponseFormatJsonObject.create()
@@ -206,15 +206,9 @@ void testTemplateFromLocalFileWithJsonSchemaAndTools() throws IOException {
206206
false);
207207
var expectedTemplateWithJsonSchemaTools =
208208
OrchestrationTemplate.create()
209-
.withTemplate(
210-
List.of(
211-
SystemChatMessage.create()
212-
.role(RoleEnum.SYSTEM)
213-
.content(ChatMessageContent.create("You are a language translator.")),
214-
UserChatMessage.create()
215-
.content(
216-
UserChatMessageContent.create("Whats {{ ?word }} in {{ ?language }}?"))
217-
.role(USER)))
209+
.withMessages(
210+
Message.system("You are a language translator."),
211+
Message.user("Whats {{ ?word }} in {{ ?language }}?"))
218212
.withDefaults(Map.of("word", "apple"))
219213
.withJsonSchemaResponse(
220214
ResponseJsonSchema.fromMap(schema, "translation-schema")
@@ -241,7 +235,12 @@ void testTemplateFromLocalFileWithJsonSchemaAndTools() throws IOException {
241235
"wordToTranslate", Map.of("type", "string"))))
242236
.description("Translate a word.")
243237
.strict(true))));
244-
assertThat(templateWithJsonSchemaTools).isEqualTo(expectedTemplateWithJsonSchemaTools);
238+
239+
var jackson = new ObjectMapper();
240+
JsonNode template = jackson.readTree(jackson.writeValueAsString(templateWithJsonSchemaTools));
241+
JsonNode expectedTemplate =
242+
jackson.readTree(jackson.writeValueAsString(expectedTemplateWithJsonSchemaTools));
243+
assertThat(template).isEqualTo(expectedTemplate);
245244
}
246245

247246
@Test
@@ -267,17 +266,16 @@ void testTemplateFromLocalFileWithJsonObject() throws IOException {
267266
var templateWithJsonObject = TemplateConfig.create().fromYaml(promptTemplateWithJsonObject);
268267
var expectedTemplateWithJsonObject =
269268
OrchestrationTemplate.create()
270-
.withTemplate(
271-
List.of(
272-
SystemChatMessage.create()
273-
.role(RoleEnum.SYSTEM)
274-
.content(ChatMessageContent.create("You are a language translator.")),
275-
UserChatMessage.create()
276-
.content(
277-
UserChatMessageContent.create("Whats {{ ?word }} in {{ ?language }}?"))
278-
.role(USER)))
269+
.withMessages(
270+
Message.system("You are a language translator."),
271+
Message.user("Whats {{ ?word }} in {{ ?language }}?"))
279272
.withDefaults(Map.of("word", "apple"))
280273
.withJsonResponse();
281-
assertThat(templateWithJsonObject).isEqualTo(expectedTemplateWithJsonObject);
274+
275+
var jackson = new ObjectMapper();
276+
JsonNode template = jackson.readTree(jackson.writeValueAsString(templateWithJsonObject));
277+
JsonNode expectedTemplate =
278+
jackson.readTree(jackson.writeValueAsString(expectedTemplateWithJsonObject));
279+
assertThat(template).isEqualTo(expectedTemplate);
282280
}
283281
}

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,11 @@ void messagesHistory() throws IOException {
413413
final List<Message> messagesHistory =
414414
List.of(
415415
new UserMessage("What is the capital of France?"),
416-
new AssistantMessage("The capital of France is Paris."));
416+
new AssistantMessage(
417+
new MessageContent(
418+
List.of(
419+
new TextItem("The capital of France is Paris."),
420+
new TextItem("Paris is known for its art, fashion, and culture.")))));
417421
final var message = new UserMessage("What is the typical food there?");
418422

419423
prompt = new OrchestrationPrompt(message).messageHistory(messagesHistory);
@@ -565,10 +569,7 @@ void testExecuteRequestFromJson() {
565569
{
566570
"messages_history": [{
567571
"role" : "user",
568-
"content" : [ {
569-
"type" : "text",
570-
"text" : "Hello World!"
571-
} ]
572+
"content" : "Hello World!"
572573
}],
573574
"input_params": {
574575
"foo" : "bar"

orchestration/src/test/resources/chatMemory.json

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,16 @@
1010
"template": [
1111
{
1212
"role": "user",
13-
"content": [ {
14-
"type" : "text",
15-
"text" : "What is the capital of France?"
16-
} ]
13+
"content": "What is the capital of France?"
1714
},
1815
{
1916
"role": "assistant",
20-
"content" : [ {
21-
"type" : "text",
22-
"text" : "Le service d'orchestration fonctionne!"
23-
} ],
17+
"content" : "Le service d'orchestration fonctionne!",
2418
"tool_calls" : [ ]
2519
},
2620
{
2721
"role": "user",
28-
"content": [ {
29-
"type" : "text",
30-
"text" : "And what is the typical food there?"
31-
} ]
22+
"content": "And what is the typical food there?"
3223
}
3324
],
3425
"defaults": {},

orchestration/src/test/resources/filteringLooseRequest.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@
1717
"template": [
1818
{
1919
"role": "user",
20-
"content": [ {
21-
"type" : "text",
22-
"text" : "Hello World! Why is this phrase so famous?"
23-
} ]
20+
"content": "Hello World! Why is this phrase so famous?"
2421
}
2522
],
2623
"defaults" : { },

0 commit comments

Comments
 (0)