diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiAssistantMessage.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiAssistantMessage.java
index d2edc094e..fd95c3389 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiAssistantMessage.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiAssistantMessage.java
@@ -2,7 +2,6 @@
import static lombok.AccessLevel.PACKAGE;
-import com.google.common.annotations.Beta;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionMessageToolCall;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionMessageToolCallFunction;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionRequestAssistantMessage;
@@ -25,7 +24,6 @@
*
* @since 1.4.0
*/
-@Beta
@Value
@Accessors(fluent = true)
@AllArgsConstructor(access = PACKAGE)
@@ -39,18 +37,14 @@ public class OpenAiAssistantMessage implements OpenAiMessage {
*
*
May contain an empty list of {@link OpenAiContentItem} when tool calls are present.
*/
- @Getter(onMethod_ = @Beta)
- @Nonnull
- OpenAiMessageContent content;
+ @Getter @Nonnull OpenAiMessageContent content;
/**
* The tool calls associated with this message if present.
*
* @since 1.6.0
*/
- @Getter(onMethod_ = @Beta)
- @Nonnull
- List toolCalls;
+ @Getter @Nonnull List toolCalls;
/**
* Creates a new assistant message with the given single message as text content.
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiChatCompletionDelta.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiChatCompletionDelta.java
index 46b5416e5..2a22c57a8 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiChatCompletionDelta.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiChatCompletionDelta.java
@@ -4,7 +4,6 @@
import static lombok.AccessLevel.PACKAGE;
import com.fasterxml.jackson.annotation.JsonCreator;
-import com.google.common.annotations.Beta;
import com.sap.ai.sdk.core.common.StreamedDelta;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.CompletionUsage;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.CreateChatCompletionStreamResponse;
@@ -22,7 +21,6 @@
*
* @since 1.4.0
*/
-@Beta
@RequiredArgsConstructor(onConstructor_ = @JsonCreator, access = PACKAGE)
@Getter
@ToString
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiChatCompletionRequest.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiChatCompletionRequest.java
index 4dfef7f39..b0345b719 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiChatCompletionRequest.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiChatCompletionRequest.java
@@ -1,6 +1,5 @@
package com.sap.ai.sdk.foundationmodels.openai;
-import com.google.common.annotations.Beta;
import com.google.common.collect.Lists;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionStreamOptions;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionTool;
@@ -30,7 +29,6 @@
* API Reference
* @since 1.4.0
*/
-@Beta
@Value
@With
@AllArgsConstructor(access = AccessLevel.PRIVATE)
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiChatCompletionResponse.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiChatCompletionResponse.java
index 32131d7b1..ec9fea99e 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiChatCompletionResponse.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiChatCompletionResponse.java
@@ -4,7 +4,6 @@
import static lombok.AccessLevel.NONE;
import static lombok.AccessLevel.PACKAGE;
-import com.google.common.annotations.Beta;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.CompletionUsage;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.CreateChatCompletionResponse;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.CreateChatCompletionResponseChoicesInner;
@@ -21,7 +20,6 @@
*
* @since 1.4.0
*/
-@Beta
@Value
@RequiredArgsConstructor(access = PACKAGE)
@Setter(value = NONE)
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiClient.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiClient.java
index 7ce79dd16..d87658d4c 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiClient.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiClient.java
@@ -101,7 +101,6 @@ public OpenAiClient withApiVersion(@Nonnull final String apiVersion) {
* @see AiCoreService#getInferenceDestination(String)
* @return a new OpenAI client.
*/
- @Beta
@Nonnull
public static OpenAiClient withCustomDestination(@Nonnull final Destination destination) {
final OpenAiClient client = new OpenAiClient(destination);
@@ -156,7 +155,6 @@ public OpenAiChatCompletionOutput chatCompletion(@Nonnull final String prompt)
* @throws OpenAiClientException if the request fails
* @since 1.4.0
*/
- @Beta
@Nonnull
public OpenAiChatCompletionResponse chatCompletion(
@Nonnull final OpenAiChatCompletionRequest request) throws OpenAiClientException {
@@ -173,7 +171,6 @@ public OpenAiChatCompletionResponse chatCompletion(
* @throws OpenAiClientException if the request fails
* @since 1.4.0
*/
- @Beta
@Nonnull
public CreateChatCompletionResponse chatCompletion(
@Nonnull final CreateChatCompletionRequest request) throws OpenAiClientException {
@@ -274,7 +271,6 @@ private static void throwOnContentFilter(@Nonnull final OpenAiChatCompletionDelt
* @see #streamChatCompletion(String)
* @since 1.4.0
*/
- @Beta
@Nonnull
public Stream streamChatCompletionDeltas(
@Nonnull final OpenAiChatCompletionRequest request) throws OpenAiClientException {
@@ -291,7 +287,6 @@ public Stream streamChatCompletionDeltas(
* @see #streamChatCompletionDeltas(OpenAiChatCompletionRequest) for a higher-level API
* @since 1.4.0
*/
- @Beta
@Nonnull
public Stream streamChatCompletionDeltas(
@Nonnull final CreateChatCompletionRequest request) throws OpenAiClientException {
@@ -358,7 +353,6 @@ private void warnIfUnsupportedUsage() {
* @see #embedding(EmbeddingsCreateRequest) for full confgurability.
* @since 1.4.0
*/
- @Beta
@Nonnull
public OpenAiEmbeddingResponse embedding(@Nonnull final OpenAiEmbeddingRequest request)
throws OpenAiClientException {
@@ -374,7 +368,6 @@ public OpenAiEmbeddingResponse embedding(@Nonnull final OpenAiEmbeddingRequest r
* @see #embedding(OpenAiEmbeddingRequest) for conveninece api
* @since 1.4.0
*/
- @Beta
@Nonnull
public EmbeddingsCreate200Response embedding(@Nonnull final EmbeddingsCreateRequest request)
throws OpenAiClientException {
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiContentItem.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiContentItem.java
index 93015ef0b..ed9433415 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiContentItem.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiContentItem.java
@@ -1,11 +1,8 @@
package com.sap.ai.sdk.foundationmodels.openai;
-import com.google.common.annotations.Beta;
-
/**
* Represents an item in a {@link OpenAiMessageContent} object.
*
* @since 1.4.0
*/
-@Beta
public sealed interface OpenAiContentItem permits OpenAiTextItem, OpenAiImageItem {}
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiEmbeddingRequest.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiEmbeddingRequest.java
index 83a029164..1f2f84918 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiEmbeddingRequest.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiEmbeddingRequest.java
@@ -1,6 +1,5 @@
package com.sap.ai.sdk.foundationmodels.openai;
-import com.google.common.annotations.Beta;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.EmbeddingsCreateRequest;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.EmbeddingsCreateRequestInput;
import java.util.Collections;
@@ -16,11 +15,10 @@
*
* @since 1.4.0
*/
-@Beta
@Value
public class OpenAiEmbeddingRequest {
/** List of tokens to be embedded. */
- @Nonnull private final List tokens;
+ @Nonnull List tokens;
/**
* Constructs an OpenAiEmbeddingRequest from a list of strings.
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiEmbeddingResponse.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiEmbeddingResponse.java
index 82bba0b45..7e05efc35 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiEmbeddingResponse.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiEmbeddingResponse.java
@@ -3,7 +3,6 @@
import static lombok.AccessLevel.NONE;
import static lombok.AccessLevel.PACKAGE;
-import com.google.common.annotations.Beta;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.EmbeddingsCreate200Response;
import java.util.ArrayList;
import java.util.List;
@@ -20,7 +19,6 @@
*
* @since 1.4.0
*/
-@Beta
@Value
@AllArgsConstructor(access = PACKAGE)
@Setter(value = NONE)
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiFunctionCall.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiFunctionCall.java
index c3668d26b..af767bfee 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiFunctionCall.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiFunctionCall.java
@@ -1,6 +1,5 @@
package com.sap.ai.sdk.foundationmodels.openai;
-import com.google.common.annotations.Beta;
import javax.annotation.Nonnull;
import lombok.AllArgsConstructor;
import lombok.Value;
@@ -10,7 +9,6 @@
*
* @since 1.6.0
*/
-@Beta
@Value
@AllArgsConstructor(access = lombok.AccessLevel.PACKAGE)
public class OpenAiFunctionCall implements OpenAiToolCall {
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiImageItem.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiImageItem.java
index 7d30a9bdd..787315b62 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiImageItem.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiImageItem.java
@@ -1,6 +1,5 @@
package com.sap.ai.sdk.foundationmodels.openai;
-import com.google.common.annotations.Beta;
import java.util.Locale;
import javax.annotation.Nonnull;
@@ -11,7 +10,6 @@
* @param detailLevel the detail level of the image (optional)
* @since 1.4.0
*/
-@Beta
public record OpenAiImageItem(@Nonnull String imageUrl, @Nonnull DetailLevel detailLevel)
implements OpenAiContentItem {
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiMessage.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiMessage.java
index 7a5b9c112..3ffd466cf 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiMessage.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiMessage.java
@@ -1,6 +1,5 @@
package com.sap.ai.sdk.foundationmodels.openai;
-import com.google.common.annotations.Beta;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
@@ -10,7 +9,6 @@
*
* @since 1.4.0
*/
-@Beta
public sealed interface OpenAiMessage
permits OpenAiUserMessage, OpenAiAssistantMessage, OpenAiSystemMessage, OpenAiToolMessage {
@@ -95,7 +93,6 @@ static OpenAiToolMessage tool(@Nonnull final String message, @Nonnull final Stri
*
* @return the content.
*/
- @Beta
@Nonnull
OpenAiMessageContent content();
}
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiMessageContent.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiMessageContent.java
index e1d49e4b7..f89a94c66 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiMessageContent.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiMessageContent.java
@@ -1,6 +1,5 @@
package com.sap.ai.sdk.foundationmodels.openai;
-import com.google.common.annotations.Beta;
import java.util.List;
import javax.annotation.Nonnull;
@@ -10,5 +9,4 @@
* @param items a list of the content items
* @since 1.4.0
*/
-@Beta
public record OpenAiMessageContent(@Nonnull List items) {}
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiSystemMessage.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiSystemMessage.java
index 9fe3a8f50..df16e13fe 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiSystemMessage.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiSystemMessage.java
@@ -2,7 +2,6 @@
import static lombok.AccessLevel.PACKAGE;
-import com.google.common.annotations.Beta;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionRequestMessageContentPartText;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionRequestSystemMessage;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionRequestSystemMessageContent;
@@ -20,7 +19,6 @@
*
* @since 1.4.0
*/
-@Beta
@Value
@Accessors(fluent = true)
@AllArgsConstructor(access = PACKAGE)
@@ -30,9 +28,7 @@ public class OpenAiSystemMessage implements OpenAiMessage {
@Nonnull String role = "system";
/** The content of the message. */
- @Getter(onMethod_ = @Beta)
- @Nonnull
- OpenAiMessageContent content;
+ @Getter @Nonnull OpenAiMessageContent content;
/**
* Creates a new system message from a string.
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiTextItem.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiTextItem.java
index 561ba2220..03413b3af 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiTextItem.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiTextItem.java
@@ -1,6 +1,5 @@
package com.sap.ai.sdk.foundationmodels.openai;
-import com.google.common.annotations.Beta;
import javax.annotation.Nonnull;
/**
@@ -9,5 +8,4 @@
* @param text the text of the item
* @since 1.4.0
*/
-@Beta
public record OpenAiTextItem(@Nonnull String text) implements OpenAiContentItem {}
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiTool.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiTool.java
index 8c14199a6..f37751183 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiTool.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiTool.java
@@ -14,7 +14,6 @@
import com.github.victools.jsonschema.generator.SchemaVersion;
import com.github.victools.jsonschema.module.jackson.JacksonModule;
import com.github.victools.jsonschema.module.jackson.JacksonOption;
-import com.google.common.annotations.Beta;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionTool;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.FunctionObject;
import java.util.ArrayList;
@@ -42,7 +41,6 @@
* @since 1.8.0
*/
@Slf4j
-@Beta
@Value
@With
@Getter(AccessLevel.PACKAGE)
@@ -165,7 +163,6 @@ private static SchemaGenerator createSchemaGenerator() {
* @param msg the assistant message containing a list of tool calls with arguments
* @return The list of tool messages with the results.
*/
- @Beta
@Nonnull
static List execute(
@Nonnull final List tools, @Nonnull final OpenAiAssistantMessage msg) {
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiToolCall.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiToolCall.java
index 9a4d3ff27..71fbf3c9f 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiToolCall.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiToolCall.java
@@ -1,6 +1,5 @@
package com.sap.ai.sdk.foundationmodels.openai;
-import com.google.common.annotations.Beta;
import javax.annotation.Nonnull;
/**
@@ -8,7 +7,6 @@
*
* @since 1.6.0
*/
-@Beta
public sealed interface OpenAiToolCall permits OpenAiFunctionCall {
/**
* Creates a new instance of {@link OpenAiToolCall}.
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiToolChoice.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiToolChoice.java
index 72824219b..0c5aea53e 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiToolChoice.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiToolChoice.java
@@ -1,6 +1,5 @@
package com.sap.ai.sdk.foundationmodels.openai;
-import com.google.common.annotations.Beta;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionNamedToolChoice;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionNamedToolChoiceFunction;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionToolChoiceOption;
@@ -14,7 +13,6 @@
*
* @since 1.4.0
*/
-@Beta
@EqualsAndHashCode
@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
public class OpenAiToolChoice {
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiToolMessage.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiToolMessage.java
index 48dca596e..bd859ec2f 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiToolMessage.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiToolMessage.java
@@ -2,7 +2,6 @@
import static lombok.AccessLevel.PACKAGE;
-import com.google.common.annotations.Beta;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionRequestToolMessage;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionRequestToolMessageContent;
import java.util.List;
@@ -16,7 +15,6 @@
*
* @since 1.4.0
*/
-@Beta
@Value
@Accessors(fluent = true)
@AllArgsConstructor(access = PACKAGE)
@@ -29,7 +27,7 @@ public class OpenAiToolMessage implements OpenAiMessage {
@Nonnull OpenAiMessageContent content;
/** The tool call id associated with this message. */
- @Nonnull private final String toolCallId;
+ @Nonnull String toolCallId;
/**
* Creates a new tool message from a tool execution response and tool call id.
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiUserMessage.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiUserMessage.java
index 4f8cc4bf6..0549297b3 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiUserMessage.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiUserMessage.java
@@ -2,7 +2,6 @@
import static lombok.AccessLevel.PACKAGE;
-import com.google.common.annotations.Beta;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionRequestMessageContentPartImage;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionRequestMessageContentPartImageImageUrl;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionRequestMessageContentPartText;
@@ -25,7 +24,6 @@
*
* @since 1.4.0
*/
-@Beta
@Value
@Accessors(fluent = true)
@AllArgsConstructor(access = PACKAGE)
@@ -35,9 +33,7 @@ public class OpenAiUserMessage implements OpenAiMessage {
@Nonnull String role = "user";
/** The content of the message. */
- @Getter(onMethod_ = @Beta)
- @Nonnull
- OpenAiMessageContent content;
+ @Getter @Nonnull OpenAiMessageContent content;
/**
* Creates a new user message from a string.
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiUtils.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiUtils.java
index 0b12565b9..18d9b6e06 100644
--- a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiUtils.java
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiUtils.java
@@ -3,7 +3,6 @@
import static com.sap.ai.sdk.core.JacksonConfiguration.getDefaultObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.annotations.Beta;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionRequestMessage;
import com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionsCreate200Response;
import javax.annotation.Nonnull;
@@ -15,7 +14,6 @@
*
* @since 1.4.0
*/
-@Beta
class OpenAiUtils {
/**
diff --git a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OpenAiController.java b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OpenAiController.java
index 76a3415a1..60dc45583 100644
--- a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OpenAiController.java
+++ b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/controllers/OpenAiController.java
@@ -4,7 +4,7 @@
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sap.ai.sdk.app.services.OpenAiService;
-import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiUsage;
+import com.sap.ai.sdk.foundationmodels.openai.generated.model.CompletionUsage;
import com.sap.cloud.sdk.cloudplatform.thread.ThreadContextExecutors;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicReference;
@@ -47,14 +47,14 @@ ResponseEntity streamChatCompletionDeltas() {
final var message = "Can you give me the first 100 numbers of the Fibonacci sequence?";
final var stream = service.streamChatCompletionDeltas(message);
final var emitter = new ResponseBodyEmitter();
- final var totalUsage = new AtomicReference();
+ final var totalUsage = new AtomicReference();
final Runnable consumeStream =
() -> {
try (stream) {
stream.forEach(
delta -> {
// Instead of getCompletionUsage(MAPPER), we now use getUsage()
- final var usage = delta.getUsage();
+ final var usage = delta.getCompletionUsage();
totalUsage.compareAndExchange(null, usage);
send(emitter, delta.getDeltaContent());
});
@@ -116,7 +116,7 @@ Object chatCompletionImage(
if ("json".equals(format)) {
return response;
}
- return response.getChoices().get(0).getMessage();
+ return response.getContent();
}
@GetMapping("/chatCompletionToolExecution")
diff --git a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OpenAiService.java b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OpenAiService.java
index 13400d059..957099c46 100644
--- a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OpenAiService.java
+++ b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OpenAiService.java
@@ -3,38 +3,29 @@
import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.GPT_4O;
import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.GPT_4O_MINI;
import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.TEXT_EMBEDDING_3_SMALL;
-import static com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionTool.ToolType.FUNCTION;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.JsonMappingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;
import com.sap.ai.sdk.core.AiCoreService;
+import com.sap.ai.sdk.foundationmodels.openai.OpenAiChatCompletionDelta;
+import com.sap.ai.sdk.foundationmodels.openai.OpenAiChatCompletionRequest;
+import com.sap.ai.sdk.foundationmodels.openai.OpenAiChatCompletionResponse;
import com.sap.ai.sdk.foundationmodels.openai.OpenAiClient;
-import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionDelta;
-import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionFunction;
-import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionOutput;
-import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionParameters;
-import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionTool;
-import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatMessage;
-import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatToolCall;
-import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiEmbeddingOutput;
-import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiEmbeddingParameters;
+import com.sap.ai.sdk.foundationmodels.openai.OpenAiEmbeddingRequest;
+import com.sap.ai.sdk.foundationmodels.openai.OpenAiEmbeddingResponse;
+import com.sap.ai.sdk.foundationmodels.openai.OpenAiImageItem;
+import com.sap.ai.sdk.foundationmodels.openai.OpenAiMessage;
+import com.sap.ai.sdk.foundationmodels.openai.OpenAiTool;
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
import java.util.stream.Stream;
import javax.annotation.Nonnull;
import lombok.extern.slf4j.Slf4j;
+import lombok.val;
import org.springframework.stereotype.Service;
-/** Service class for OpenAI service */
+/** Service class for OpenAI service using latest convenience api */
@Service
@Slf4j
public class OpenAiService {
- private static final ObjectMapper JACKSON = new ObjectMapper();
-
/**
* Chat request to OpenAI
*
@@ -42,8 +33,31 @@ public class OpenAiService {
* @return the assistant message response
*/
@Nonnull
- public OpenAiChatCompletionOutput chatCompletion(@Nonnull final String prompt) {
- return OpenAiClient.forModel(GPT_4O_MINI).chatCompletion(prompt);
+ public OpenAiChatCompletionResponse chatCompletion(@Nonnull final String prompt) {
+ return OpenAiClient.forModel(GPT_4O_MINI)
+ .chatCompletion(new OpenAiChatCompletionRequest(prompt));
+ }
+
+ /**
+ * Chat requests to OpenAI and updating the messages history
+ *
+ * @param previousMessage The request to send to the assistant
+ * @return the assistant message response
+ */
+ @Nonnull
+ public OpenAiChatCompletionResponse messagesHistory(@Nonnull final String previousMessage) {
+ val messagesList = new ArrayList();
+ messagesList.add(OpenAiMessage.user(previousMessage));
+
+ final OpenAiChatCompletionResponse result =
+ OpenAiClient.forModel(GPT_4O_MINI)
+ .chatCompletion(new OpenAiChatCompletionRequest(messagesList));
+
+ messagesList.add(result.getMessage());
+ messagesList.add(OpenAiMessage.user("What is the typical food there?"));
+
+ return OpenAiClient.forModel(GPT_4O_MINI)
+ .chatCompletion(new OpenAiChatCompletionRequest(messagesList));
}
/**
@@ -55,9 +69,7 @@ public OpenAiChatCompletionOutput chatCompletion(@Nonnull final String prompt) {
@Nonnull
public Stream streamChatCompletionDeltas(
@Nonnull final String message) {
- final var request =
- new OpenAiChatCompletionParameters()
- .addMessages(new OpenAiChatMessage.OpenAiChatUserMessage().addText(message));
+ final var request = new OpenAiChatCompletionRequest(OpenAiMessage.user(message));
return OpenAiClient.forModel(GPT_4O_MINI).streamChatCompletionDeltas(request);
}
@@ -82,93 +94,50 @@ public Stream streamChatCompletion(@Nonnull final String message) {
* @return the assistant message response
*/
@Nonnull
- public OpenAiChatCompletionOutput chatCompletionImage(@Nonnull final String linkToImage) {
- final var request =
- new OpenAiChatCompletionParameters()
- .addMessages(
- new OpenAiChatMessage.OpenAiChatUserMessage()
- .addText("Describe the following image.")
- .addImage(
- linkToImage,
- OpenAiChatMessage.OpenAiChatUserMessage.ImageDetailLevel.HIGH));
-
- return OpenAiClient.forModel(GPT_4O).chatCompletion(request);
+ public OpenAiChatCompletionResponse chatCompletionImage(@Nonnull final String linkToImage) {
+
+ final var userMessage =
+ OpenAiMessage.user("Describe the following image.")
+ .withImage(linkToImage, OpenAiImageItem.DetailLevel.HIGH);
+
+ return OpenAiClient.forModel(GPT_4O)
+ .chatCompletion(new OpenAiChatCompletionRequest(userMessage));
}
/**
- * Executes a chat completion request to OpenAI with a tool that calculates the weather.
+ * Chat request to OpenAI with tool that gets the weather for a given location and unit. The tool
+ * executed and the result is sent back to the assistant.
*
* @param location The location to get the weather for.
* @param unit The unit of temperature to use.
* @return The assistant message response.
*/
@Nonnull
- public OpenAiChatCompletionOutput chatCompletionToolExecution(
+ public OpenAiChatCompletionResponse chatCompletionToolExecution(
@Nonnull final String location, @Nonnull final String unit) {
+ final OpenAiClient client = OpenAiClient.forModel(GPT_4O_MINI);
- // 1. Define the function
- final Map schemaMap = generateSchema(WeatherMethod.Request.class);
- final var function =
- new OpenAiChatCompletionFunction()
- .setName("weather")
- .setDescription("Get the weather for the given location")
- .setParameters(schemaMap);
- final var tool = new OpenAiChatCompletionTool().setType(FUNCTION).setFunction(function);
-
- final var messages = new ArrayList();
- messages.add(
- new OpenAiChatMessage.OpenAiChatUserMessage()
- .addText("What's the weather in %s in %s?".formatted(location, unit)));
-
- // Assistant will call the function
- final var request =
- new OpenAiChatCompletionParameters()
- .addMessages(messages.toArray(OpenAiChatMessage[]::new))
- .setTools(List.of(tool));
-
- final OpenAiChatCompletionOutput response =
- OpenAiClient.forModel(GPT_4O_MINI).chatCompletion(request);
-
- // 2. Optionally, execute the function.
- final OpenAiChatToolCall toolCall =
- response.getChoices().get(0).getMessage().getToolCalls().get(0);
- final WeatherMethod.Request arguments =
- parseJson(toolCall.getFunction().getArguments(), WeatherMethod.Request.class);
- final WeatherMethod.Response currentWeather = WeatherMethod.getCurrentWeather(arguments);
-
- final OpenAiChatMessage.OpenAiChatAssistantMessage assistantMessage =
- response.getChoices().get(0).getMessage();
- messages.add(assistantMessage);
-
- final var toolMessage =
- new OpenAiChatMessage.OpenAiChatToolMessage()
- .setToolCallId(toolCall.getId())
- .setContent(currentWeather.toString());
- messages.add(toolMessage);
-
- final var finalRequest =
- new OpenAiChatCompletionParameters()
- .addMessages(messages.toArray(OpenAiChatMessage[]::new));
-
- return OpenAiClient.forModel(GPT_4O_MINI).chatCompletion(finalRequest);
- }
+ final var messages = new ArrayList();
+ messages.add(OpenAiMessage.user("What's the weather in %s in %s?".formatted(location, unit)));
- private static T parseJson(@Nonnull final String rawJson, @Nonnull final Class clazz) {
- try {
- return JACKSON.readValue(rawJson, clazz);
- } catch (JsonProcessingException e) {
- throw new IllegalArgumentException("Failed to parse tool call arguments: " + rawJson, e);
- }
- }
-
- private static Map generateSchema(@Nonnull final Class> clazz) {
- final var jsonSchemaGenerator = new JsonSchemaGenerator(JACKSON);
- try {
- final var schema = jsonSchemaGenerator.generateSchema(clazz);
- return JACKSON.convertValue(schema, new TypeReference<>() {});
- } catch (JsonMappingException e) {
- throw new IllegalArgumentException("Could not generate schema for " + clazz.getName(), e);
- }
+ // 1. Define the function
+ final List tools =
+ List.of(
+ OpenAiTool.forFunction(WeatherMethod::getCurrentWeather)
+ .withArgument(WeatherMethod.Request.class)
+ .withName("weather")
+ .withDescription("Get the weather for the given location"));
+
+ // 2. Assistant calls the function
+ final var request = new OpenAiChatCompletionRequest(messages).withToolsExecutable(tools);
+ final OpenAiChatCompletionResponse response = client.chatCompletion(request);
+
+ // 3. Execute the tool calls
+ messages.add(response.getMessage());
+ messages.addAll(response.executeTools());
+
+ // 4. Have model run the final request with incorporated tool results
+ return client.chatCompletion(request.withMessages(messages));
}
/**
@@ -178,8 +147,8 @@ private static Map generateSchema(@Nonnull final Class> clazz)
* @return the embedding response
*/
@Nonnull
- public OpenAiEmbeddingOutput embedding(@Nonnull final String input) {
- final var request = new OpenAiEmbeddingParameters().setInput(input);
+ public OpenAiEmbeddingResponse embedding(@Nonnull final String input) {
+ final var request = new OpenAiEmbeddingRequest(List.of(input));
return OpenAiClient.forModel(TEXT_EMBEDDING_3_SMALL).embedding(request);
}
@@ -192,12 +161,13 @@ public OpenAiEmbeddingOutput embedding(@Nonnull final String input) {
* @return the assistant message response
*/
@Nonnull
- public OpenAiChatCompletionOutput chatCompletionWithResource(
+ public OpenAiChatCompletionResponse chatCompletionWithResource(
@Nonnull final String resourceGroup, @Nonnull final String prompt) {
final var destination =
new AiCoreService().getInferenceDestination(resourceGroup).forModel(GPT_4O);
- return OpenAiClient.withCustomDestination(destination).chatCompletion(prompt);
+ return OpenAiClient.withCustomDestination(destination)
+ .chatCompletion(new OpenAiChatCompletionRequest(prompt));
}
}
diff --git a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OpenAiServiceDeprecated.java b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OpenAiServiceDeprecated.java
new file mode 100644
index 000000000..60c42c4ce
--- /dev/null
+++ b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OpenAiServiceDeprecated.java
@@ -0,0 +1,204 @@
+package com.sap.ai.sdk.app.services;
+
+import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.GPT_4O;
+import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.GPT_4O_MINI;
+import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.TEXT_EMBEDDING_3_SMALL;
+import static com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionTool.ToolType.FUNCTION;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;
+import com.sap.ai.sdk.core.AiCoreService;
+import com.sap.ai.sdk.foundationmodels.openai.OpenAiClient;
+import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionDelta;
+import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionFunction;
+import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionOutput;
+import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionParameters;
+import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionTool;
+import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatMessage;
+import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatToolCall;
+import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiEmbeddingOutput;
+import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiEmbeddingParameters;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+import javax.annotation.Nonnull;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/** Service class for OpenAI service */
+@Service
+@Slf4j
+@Deprecated
+public class OpenAiServiceDeprecated {
+ private static final ObjectMapper JACKSON = new ObjectMapper();
+
+ /**
+ * Chat request to OpenAI
+ *
+ * @param prompt The prompt to send to the assistant
+ * @return the assistant message response
+ */
+ @Nonnull
+ public OpenAiChatCompletionOutput chatCompletion(@Nonnull final String prompt) {
+ return OpenAiClient.forModel(GPT_4O_MINI).chatCompletion(prompt);
+ }
+
+ /**
+ * Asynchronous stream of an OpenAI chat request
+ *
+ * @param message The message to send to the assistant
+ * @return the emitter that streams the assistant message response
+ */
+ @Nonnull
+ public Stream streamChatCompletionDeltas(
+ @Nonnull final String message) {
+ final var request =
+ new OpenAiChatCompletionParameters()
+ .addMessages(new OpenAiChatMessage.OpenAiChatUserMessage().addText(message));
+
+ return OpenAiClient.forModel(GPT_4O_MINI).streamChatCompletionDeltas(request);
+ }
+
+ /**
+ * Asynchronous stream of an OpenAI chat request
+ *
+ * @param message The message to send to the assistant
+ * @return the emitter that streams the assistant message response
+ */
+ @Nonnull
+ public Stream streamChatCompletion(@Nonnull final String message) {
+ return OpenAiClient.forModel(GPT_4O_MINI)
+ .withSystemPrompt("Be a good, honest AI and answer the following question:")
+ .streamChatCompletion(message);
+ }
+
+ /**
+ * Chat request to OpenAI with an image
+ *
+ * @param linkToImage The link to the image
+ * @return the assistant message response
+ */
+ @Nonnull
+ public OpenAiChatCompletionOutput chatCompletionImage(@Nonnull final String linkToImage) {
+ final var request =
+ new OpenAiChatCompletionParameters()
+ .addMessages(
+ new OpenAiChatMessage.OpenAiChatUserMessage()
+ .addText("Describe the following image.")
+ .addImage(
+ linkToImage,
+ OpenAiChatMessage.OpenAiChatUserMessage.ImageDetailLevel.HIGH));
+
+ return OpenAiClient.forModel(GPT_4O).chatCompletion(request);
+ }
+
+ /**
+ * Executes a chat completion request to OpenAI with a tool that calculates the weather.
+ *
+ * @param location The location to get the weather for.
+ * @param unit The unit of temperature to use.
+ * @return The assistant message response.
+ */
+ @Nonnull
+ public OpenAiChatCompletionOutput chatCompletionToolExecution(
+ @Nonnull final String location, @Nonnull final String unit) {
+
+ // 1. Define the function
+ final Map schemaMap = generateSchema(WeatherMethod.Request.class);
+ final var function =
+ new OpenAiChatCompletionFunction()
+ .setName("weather")
+ .setDescription("Get the weather for the given location")
+ .setParameters(schemaMap);
+ final var tool = new OpenAiChatCompletionTool().setType(FUNCTION).setFunction(function);
+
+ final var messages = new ArrayList();
+ messages.add(
+ new OpenAiChatMessage.OpenAiChatUserMessage()
+ .addText("What's the weather in %s in %s?".formatted(location, unit)));
+
+ // Assistant will call the function
+ final var request =
+ new OpenAiChatCompletionParameters()
+ .addMessages(messages.toArray(OpenAiChatMessage[]::new))
+ .setTools(List.of(tool));
+
+ final OpenAiChatCompletionOutput response =
+ OpenAiClient.forModel(GPT_4O_MINI).chatCompletion(request);
+
+ // 2. Optionally, execute the function.
+ final OpenAiChatToolCall toolCall =
+ response.getChoices().get(0).getMessage().getToolCalls().get(0);
+ final WeatherMethod.Request arguments =
+ parseJson(toolCall.getFunction().getArguments(), WeatherMethod.Request.class);
+ final WeatherMethod.Response currentWeather = WeatherMethod.getCurrentWeather(arguments);
+
+ final OpenAiChatMessage.OpenAiChatAssistantMessage assistantMessage =
+ response.getChoices().get(0).getMessage();
+ messages.add(assistantMessage);
+
+ final var toolMessage =
+ new OpenAiChatMessage.OpenAiChatToolMessage()
+ .setToolCallId(toolCall.getId())
+ .setContent(currentWeather.toString());
+ messages.add(toolMessage);
+
+ final var finalRequest =
+ new OpenAiChatCompletionParameters()
+ .addMessages(messages.toArray(OpenAiChatMessage[]::new));
+
+ return OpenAiClient.forModel(GPT_4O_MINI).chatCompletion(finalRequest);
+ }
+
+ private static T parseJson(@Nonnull final String rawJson, @Nonnull final Class clazz) {
+ try {
+ return JACKSON.readValue(rawJson, clazz);
+ } catch (JsonProcessingException e) {
+ throw new IllegalArgumentException("Failed to parse tool call arguments: " + rawJson, e);
+ }
+ }
+
+ private static Map generateSchema(@Nonnull final Class> clazz) {
+ final var jsonSchemaGenerator = new JsonSchemaGenerator(JACKSON);
+ try {
+ final var schema = jsonSchemaGenerator.generateSchema(clazz);
+ return JACKSON.convertValue(schema, new TypeReference<>() {});
+ } catch (JsonMappingException e) {
+ throw new IllegalArgumentException("Could not generate schema for " + clazz.getName(), e);
+ }
+ }
+
+ /**
+ * Get the embedding of a text
+ *
+ * @param input The text to embed
+ * @return the embedding response
+ */
+ @Nonnull
+ public OpenAiEmbeddingOutput embedding(@Nonnull final String input) {
+ final var request = new OpenAiEmbeddingParameters().setInput(input);
+
+ return OpenAiClient.forModel(TEXT_EMBEDDING_3_SMALL).embedding(request);
+ }
+
+ /**
+ * Chat request to OpenAI filtering by resource group
+ *
+ * @param resourceGroup The resource group to use
+ * @param prompt The prompt to send to the assistant
+ * @return the assistant message response
+ */
+ @Nonnull
+ public OpenAiChatCompletionOutput chatCompletionWithResource(
+ @Nonnull final String resourceGroup, @Nonnull final String prompt) {
+
+ final var destination =
+ new AiCoreService().getInferenceDestination(resourceGroup).forModel(GPT_4O);
+
+ return OpenAiClient.withCustomDestination(destination).chatCompletion(prompt);
+ }
+}
diff --git a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OpenAiServiceV2.java b/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OpenAiServiceV2.java
deleted file mode 100644
index b0b3acbd9..000000000
--- a/sample-code/spring-app/src/main/java/com/sap/ai/sdk/app/services/OpenAiServiceV2.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package com.sap.ai.sdk.app.services;
-
-import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.GPT_4O;
-import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.GPT_4O_MINI;
-import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.TEXT_EMBEDDING_3_SMALL;
-
-import com.sap.ai.sdk.core.AiCoreService;
-import com.sap.ai.sdk.foundationmodels.openai.OpenAiChatCompletionDelta;
-import com.sap.ai.sdk.foundationmodels.openai.OpenAiChatCompletionRequest;
-import com.sap.ai.sdk.foundationmodels.openai.OpenAiChatCompletionResponse;
-import com.sap.ai.sdk.foundationmodels.openai.OpenAiClient;
-import com.sap.ai.sdk.foundationmodels.openai.OpenAiEmbeddingRequest;
-import com.sap.ai.sdk.foundationmodels.openai.OpenAiEmbeddingResponse;
-import com.sap.ai.sdk.foundationmodels.openai.OpenAiImageItem;
-import com.sap.ai.sdk.foundationmodels.openai.OpenAiMessage;
-import com.sap.ai.sdk.foundationmodels.openai.OpenAiTool;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Stream;
-import javax.annotation.Nonnull;
-import lombok.extern.slf4j.Slf4j;
-import lombok.val;
-import org.springframework.stereotype.Service;
-
-/** Service class for OpenAI service using latest convenience api */
-@Service
-@Slf4j
-public class OpenAiServiceV2 {
- /**
- * Chat request to OpenAI
- *
- * @param prompt The prompt to send to the assistant
- * @return the assistant message response
- */
- @Nonnull
- public OpenAiChatCompletionResponse chatCompletion(@Nonnull final String prompt) {
- return OpenAiClient.forModel(GPT_4O_MINI)
- .chatCompletion(new OpenAiChatCompletionRequest(prompt));
- }
-
- /**
- * Chat requests to OpenAI and updating the messages history
- *
- * @param previousMessage The request to send to the assistant
- * @return the assistant message response
- */
- @Nonnull
- public OpenAiChatCompletionResponse messagesHistory(@Nonnull final String previousMessage) {
- val messagesList = new ArrayList();
- messagesList.add(OpenAiMessage.user(previousMessage));
-
- final OpenAiChatCompletionResponse result =
- OpenAiClient.forModel(GPT_4O_MINI)
- .chatCompletion(new OpenAiChatCompletionRequest(messagesList));
-
- messagesList.add(result.getMessage());
- messagesList.add(OpenAiMessage.user("What is the typical food there?"));
-
- return OpenAiClient.forModel(GPT_4O_MINI)
- .chatCompletion(new OpenAiChatCompletionRequest(messagesList));
- }
-
- /**
- * Asynchronous stream of an OpenAI chat request
- *
- * @param message The message to send to the assistant
- * @return the emitter that streams the assistant message response
- */
- @Nonnull
- public Stream streamChatCompletionDeltas(
- @Nonnull final String message) {
- final var request = new OpenAiChatCompletionRequest(OpenAiMessage.user(message));
-
- return OpenAiClient.forModel(GPT_4O_MINI).streamChatCompletionDeltas(request);
- }
-
- /**
- * Asynchronous stream of an OpenAI chat request
- *
- * @param message The message to send to the assistant
- * @return the emitter that streams the assistant message response
- */
- @Nonnull
- public Stream streamChatCompletion(@Nonnull final String message) {
- return OpenAiClient.forModel(GPT_4O_MINI)
- .withSystemPrompt("Be a good, honest AI and answer the following question:")
- .streamChatCompletion(message);
- }
-
- /**
- * Chat request to OpenAI with an image
- *
- * @param linkToImage The link to the image
- * @return the assistant message response
- */
- @Nonnull
- public OpenAiChatCompletionResponse chatCompletionImage(@Nonnull final String linkToImage) {
-
- final var userMessage =
- OpenAiMessage.user("Describe the following image.")
- .withImage(linkToImage, OpenAiImageItem.DetailLevel.HIGH);
-
- return OpenAiClient.forModel(GPT_4O)
- .chatCompletion(new OpenAiChatCompletionRequest(userMessage));
- }
-
- /**
- * Chat request to OpenAI with tool that gets the weather for a given location and unit. The tool
- * executed and the result is sent back to the assistant.
- *
- * @param location The location to get the weather for.
- * @param unit The unit of temperature to use.
- * @return The assistant message response.
- */
- @Nonnull
- public OpenAiChatCompletionResponse chatCompletionToolExecution(
- @Nonnull final String location, @Nonnull final String unit) {
- final OpenAiClient client = OpenAiClient.forModel(GPT_4O_MINI);
-
- final var messages = new ArrayList();
- messages.add(OpenAiMessage.user("What's the weather in %s in %s?".formatted(location, unit)));
-
- // 1. Define the function
- final List tools =
- List.of(
- OpenAiTool.forFunction(WeatherMethod::getCurrentWeather)
- .withArgument(WeatherMethod.Request.class)
- .withName("weather")
- .withDescription("Get the weather for the given location"));
-
- // 2. Assistant calls the function
- final var request = new OpenAiChatCompletionRequest(messages).withToolsExecutable(tools);
- final OpenAiChatCompletionResponse response = client.chatCompletion(request);
-
- // 3. Execute the tool calls
- messages.add(response.getMessage());
- messages.addAll(response.executeTools());
-
- // 4. Have model run the final request with incorporated tool results
- return client.chatCompletion(request.withMessages(messages));
- }
-
- /**
- * Get the embedding of a text
- *
- * @param input The text to embed
- * @return the embedding response
- */
- @Nonnull
- public OpenAiEmbeddingResponse embedding(@Nonnull final String input) {
- final var request = new OpenAiEmbeddingRequest(List.of(input));
-
- return OpenAiClient.forModel(TEXT_EMBEDDING_3_SMALL).embedding(request);
- }
-
- /**
- * Chat request to OpenAI filtering by resource group
- *
- * @param resourceGroup The resource group to use
- * @param prompt The prompt to send to the assistant
- * @return the assistant message response
- */
- @Nonnull
- public OpenAiChatCompletionResponse chatCompletionWithResource(
- @Nonnull final String resourceGroup, @Nonnull final String prompt) {
-
- final var destination =
- new AiCoreService().getInferenceDestination(resourceGroup).forModel(GPT_4O);
-
- return OpenAiClient.withCustomDestination(destination)
- .chatCompletion(new OpenAiChatCompletionRequest(prompt));
- }
-}
diff --git a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OpenAiDeprecatedTest.java b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OpenAiDeprecatedTest.java
new file mode 100644
index 000000000..afc76461d
--- /dev/null
+++ b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OpenAiDeprecatedTest.java
@@ -0,0 +1,103 @@
+package com.sap.ai.sdk.app.controllers;
+
+import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.GPT_4O_MINI;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.sap.ai.sdk.app.services.OpenAiServiceDeprecated;
+import com.sap.ai.sdk.foundationmodels.openai.OpenAiClient;
+import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionOutput;
+import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionParameters;
+import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatMessage.OpenAiChatUserMessage;
+import java.util.concurrent.atomic.AtomicInteger;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+@Slf4j
+class OpenAiDeprecatedTest {
+ OpenAiServiceDeprecated service;
+
+ @BeforeEach
+ void setUp() {
+ service = new OpenAiServiceDeprecated();
+ }
+
+ @Test
+ void chatCompletion() {
+ final var completion = service.chatCompletion("Who is the prettiest");
+
+ final var message = completion.getChoices().get(0).getMessage();
+ assertThat(message.getRole()).isEqualTo("assistant");
+ assertThat(message.getContent()).isNotEmpty();
+ }
+
+ @Test
+ void chatCompletionImage() {
+ final var completion =
+ service.chatCompletionImage(
+ "https://upload.wikimedia.org/wikipedia/commons/thumb/5/59/SAP_2011_logo.svg/440px-SAP_2011_logo.svg.png");
+
+ final var message = completion.getChoices().get(0).getMessage();
+ assertThat(message.getRole()).isEqualTo("assistant");
+ assertThat(message.getContent()).isNotEmpty();
+ }
+
+ @Test
+ void streamChatCompletion() {
+ final var request =
+ new OpenAiChatCompletionParameters()
+ .addMessages(new OpenAiChatUserMessage().addText("Who is the prettiest?"));
+
+ final var totalOutput = new OpenAiChatCompletionOutput();
+ final var filledDeltaCount = new AtomicInteger(0);
+ OpenAiClient.forModel(GPT_4O_MINI)
+ .streamChatCompletionDeltas(request)
+ .peek(totalOutput::addDelta)
+ // foreach consumes all elements, closing the stream at the end
+ .forEach(
+ delta -> {
+ final String deltaContent = delta.getDeltaContent();
+ log.info("delta: {}", delta);
+ if (!deltaContent.isEmpty()) {
+ filledDeltaCount.incrementAndGet();
+ }
+ });
+
+ // the first two and the last delta don't have any content
+ // see OpenAiChatCompletionDelta#getDeltaContent
+ assertThat(filledDeltaCount.get()).isGreaterThan(0);
+
+ assertThat(totalOutput.getChoices()).isNotEmpty();
+ assertThat(totalOutput.getChoices().get(0).getMessage().getContent()).isNotEmpty();
+ assertThat(totalOutput.getPromptFilterResults()).isNotNull();
+ assertThat(totalOutput.getChoices().get(0).getContentFilterResults()).isNotNull();
+ }
+
+ @Test
+ void embedding() {
+ final var embedding = service.embedding("Hello world");
+
+ assertThat(embedding.getData().get(0).getEmbedding()).hasSizeGreaterThan(1);
+ assertThat(embedding.getModel()).isEqualTo("text-embedding-3-small");
+ assertThat(embedding.getObject()).isEqualTo("list");
+ }
+
+ @Test
+ void chatCompletionWithResource() {
+ final var completion =
+ service.chatCompletionWithResource("ai-sdk-java-e2e", "Where is the nearest coffee shop?");
+
+ final var message = completion.getChoices().get(0).getMessage();
+ assertThat(message.getRole()).isEqualTo("assistant");
+ assertThat(message.getContent()).isNotEmpty();
+ }
+
+ @Test
+ void chatCompletionToolExecution() {
+ final var completion = service.chatCompletionToolExecution("Dubai", "°C");
+
+ String content = completion.getContent();
+
+ assertThat(content).contains("°C");
+ }
+}
diff --git a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OpenAiTest.java b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OpenAiTest.java
index 7a029ebdd..6a541d489 100644
--- a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OpenAiTest.java
+++ b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OpenAiTest.java
@@ -1,14 +1,17 @@
package com.sap.ai.sdk.app.controllers;
import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.GPT_4O_MINI;
+import static com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionResponseMessageRole.ASSISTANT;
import static org.assertj.core.api.Assertions.assertThat;
import com.sap.ai.sdk.app.services.OpenAiService;
+import com.sap.ai.sdk.foundationmodels.openai.OpenAiChatCompletionRequest;
import com.sap.ai.sdk.foundationmodels.openai.OpenAiClient;
-import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionOutput;
-import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatCompletionParameters;
-import com.sap.ai.sdk.foundationmodels.openai.model.OpenAiChatMessage.OpenAiChatUserMessage;
+import com.sap.ai.sdk.foundationmodels.openai.OpenAiMessage;
+import com.sap.ai.sdk.foundationmodels.openai.generated.model.CompletionUsage;
+import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -26,9 +29,13 @@ void setUp() {
void chatCompletion() {
final var completion = service.chatCompletion("Who is the prettiest");
- final var message = completion.getChoices().get(0).getMessage();
- assertThat(message.getRole()).isEqualTo("assistant");
- assertThat(message.getContent()).isNotEmpty();
+ assertThat(completion.getChoice().getMessage().getRole()).isEqualTo(ASSISTANT);
+ assertThat(completion.getContent()).isNotEmpty();
+ }
+
+ @Test
+ void testMessagesHistory() {
+ assertThat(service.messagesHistory("What is the capital of France?").getContent()).isNotEmpty();
}
@Test
@@ -37,25 +44,24 @@ void chatCompletionImage() {
service.chatCompletionImage(
"https://upload.wikimedia.org/wikipedia/commons/thumb/5/59/SAP_2011_logo.svg/440px-SAP_2011_logo.svg.png");
- final var message = completion.getChoices().get(0).getMessage();
- assertThat(message.getRole()).isEqualTo("assistant");
- assertThat(message.getContent()).isNotEmpty();
+ assertThat(completion.getContent()).isNotEmpty();
+ assertThat(completion.getChoice().getMessage().getRole()).isEqualTo(ASSISTANT);
}
@Test
void streamChatCompletion() {
- final var request =
- new OpenAiChatCompletionParameters()
- .addMessages(new OpenAiChatUserMessage().addText("Who is the prettiest?"));
+ final var userMessage = OpenAiMessage.user("Who is the prettiest?");
+ final var prompt = new OpenAiChatCompletionRequest(userMessage);
- final var totalOutput = new OpenAiChatCompletionOutput();
+ final var usageRef = new AtomicReference();
final var filledDeltaCount = new AtomicInteger(0);
+
OpenAiClient.forModel(GPT_4O_MINI)
- .streamChatCompletionDeltas(request)
- .peek(totalOutput::addDelta)
+ .streamChatCompletionDeltas(prompt)
// foreach consumes all elements, closing the stream at the end
.forEach(
delta -> {
+ usageRef.compareAndExchange(null, delta.getCompletionUsage());
final String deltaContent = delta.getDeltaContent();
log.info("delta: {}", delta);
if (!deltaContent.isEmpty()) {
@@ -63,23 +69,24 @@ void streamChatCompletion() {
}
});
- // the first two and the last delta don't have any content
- // see OpenAiChatCompletionDelta#getDeltaContent
assertThat(filledDeltaCount.get()).isGreaterThan(0);
- assertThat(totalOutput.getChoices()).isNotEmpty();
- assertThat(totalOutput.getChoices().get(0).getMessage().getContent()).isNotEmpty();
- assertThat(totalOutput.getPromptFilterResults()).isNotNull();
- assertThat(totalOutput.getChoices().get(0).getContentFilterResults()).isNotNull();
+ assertThat(usageRef.get().getTotalTokens()).isGreaterThan(0);
+ assertThat(usageRef.get().getPromptTokens()).isGreaterThan(0);
+ assertThat(usageRef.get().getCompletionTokens()).isGreaterThan(0);
}
@Test
void embedding() {
final var embedding = service.embedding("Hello world");
- assertThat(embedding.getData().get(0).getEmbedding()).hasSizeGreaterThan(1);
- assertThat(embedding.getModel()).isEqualTo("text-embedding-3-small");
- assertThat(embedding.getObject()).isEqualTo("list");
+ assertThat(embedding.getOriginalResponse().getData().get(0).getEmbedding())
+ .hasSizeGreaterThan(1);
+ assertThat(embedding.getEmbeddingVectors()).isInstanceOf(ArrayList.class);
+ assertThat(embedding.getEmbeddingVectors().get(0)).isInstanceOf(float[].class);
+
+ assertThat(embedding.getOriginalResponse().getModel()).isEqualTo("text-embedding-3-small");
+ assertThat(embedding.getOriginalResponse().getObject()).isEqualTo("list");
}
@Test
@@ -87,9 +94,8 @@ void chatCompletionWithResource() {
final var completion =
service.chatCompletionWithResource("ai-sdk-java-e2e", "Where is the nearest coffee shop?");
- final var message = completion.getChoices().get(0).getMessage();
- assertThat(message.getRole()).isEqualTo("assistant");
- assertThat(message.getContent()).isNotEmpty();
+ assertThat(completion.getChoice().getMessage().getRole()).isEqualTo(ASSISTANT);
+ assertThat(completion.getContent()).isNotEmpty();
}
@Test
diff --git a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OpenAiV2Test.java b/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OpenAiV2Test.java
deleted file mode 100644
index 9f89f1da5..000000000
--- a/sample-code/spring-app/src/test/java/com/sap/ai/sdk/app/controllers/OpenAiV2Test.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package com.sap.ai.sdk.app.controllers;
-
-import static com.sap.ai.sdk.foundationmodels.openai.OpenAiModel.GPT_4O_MINI;
-import static com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionResponseMessageRole.ASSISTANT;
-import static org.assertj.core.api.Assertions.assertThat;
-
-import com.sap.ai.sdk.app.services.OpenAiServiceV2;
-import com.sap.ai.sdk.foundationmodels.openai.OpenAiChatCompletionRequest;
-import com.sap.ai.sdk.foundationmodels.openai.OpenAiClient;
-import com.sap.ai.sdk.foundationmodels.openai.OpenAiMessage;
-import com.sap.ai.sdk.foundationmodels.openai.generated.model.CompletionUsage;
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import lombok.extern.slf4j.Slf4j;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-@Slf4j
-class OpenAiV2Test {
- OpenAiServiceV2 service;
-
- @BeforeEach
- void setUp() {
- service = new OpenAiServiceV2();
- }
-
- @Test
- void chatCompletion() {
- final var completion = service.chatCompletion("Who is the prettiest");
-
- assertThat(completion.getChoice().getMessage().getRole()).isEqualTo(ASSISTANT);
- assertThat(completion.getContent()).isNotEmpty();
- }
-
- @Test
- void testMessagesHistory() {
- assertThat(service.messagesHistory("What is the capital of France?").getContent()).isNotEmpty();
- }
-
- @Test
- void chatCompletionImage() {
- final var completion =
- service.chatCompletionImage(
- "https://upload.wikimedia.org/wikipedia/commons/thumb/5/59/SAP_2011_logo.svg/440px-SAP_2011_logo.svg.png");
-
- assertThat(completion.getContent()).isNotEmpty();
- assertThat(completion.getChoice().getMessage().getRole()).isEqualTo(ASSISTANT);
- }
-
- @Test
- void streamChatCompletion() {
- final var userMessage = OpenAiMessage.user("Who is the prettiest?");
- final var prompt = new OpenAiChatCompletionRequest(userMessage);
-
- final var usageRef = new AtomicReference();
- final var filledDeltaCount = new AtomicInteger(0);
-
- OpenAiClient.forModel(GPT_4O_MINI)
- .streamChatCompletionDeltas(prompt)
- // foreach consumes all elements, closing the stream at the end
- .forEach(
- delta -> {
- usageRef.compareAndExchange(null, delta.getCompletionUsage());
- final String deltaContent = delta.getDeltaContent();
- log.info("delta: {}", delta);
- if (!deltaContent.isEmpty()) {
- filledDeltaCount.incrementAndGet();
- }
- });
-
- assertThat(filledDeltaCount.get()).isGreaterThan(0);
-
- assertThat(usageRef.get().getTotalTokens()).isGreaterThan(0);
- assertThat(usageRef.get().getPromptTokens()).isGreaterThan(0);
- assertThat(usageRef.get().getCompletionTokens()).isGreaterThan(0);
- }
-
- @Test
- void embedding() {
- final var embedding = service.embedding("Hello world");
-
- assertThat(embedding.getOriginalResponse().getData().get(0).getEmbedding())
- .hasSizeGreaterThan(1);
- assertThat(embedding.getEmbeddingVectors()).isInstanceOf(ArrayList.class);
- assertThat(embedding.getEmbeddingVectors().get(0)).isInstanceOf(float[].class);
-
- assertThat(embedding.getOriginalResponse().getModel()).isEqualTo("text-embedding-3-small");
- assertThat(embedding.getOriginalResponse().getObject()).isEqualTo("list");
- }
-
- @Test
- void chatCompletionWithResource() {
- final var completion =
- service.chatCompletionWithResource("ai-sdk-java-e2e", "Where is the nearest coffee shop?");
-
- assertThat(completion.getChoice().getMessage().getRole()).isEqualTo(ASSISTANT);
- assertThat(completion.getContent()).isNotEmpty();
- }
-
- @Test
- void chatCompletionToolExecution() {
- final var completion = service.chatCompletionToolExecution("Dubai", "°C");
-
- String content = completion.getContent();
-
- assertThat(content).contains("°C");
- }
-}