diff --git a/docs/release_notes.md b/docs/release_notes.md
index 5745d6681..490694854 100644
--- a/docs/release_notes.md
+++ b/docs/release_notes.md
@@ -12,7 +12,7 @@
### ✨ New Functionality
--
+- [OpenAI] [Add convenience for tool definition and parsing function calls](https://sap.github.io/ai-sdk/docs/java/foundation-models/openai/chat-completion#executing-tool-calls)
### 📈 Improvements
diff --git a/foundation-models/openai/pom.xml b/foundation-models/openai/pom.xml
index bb3eb499a..f9d31ef36 100644
--- a/foundation-models/openai/pom.xml
+++ b/foundation-models/openai/pom.xml
@@ -77,6 +77,10 @@
com.fasterxml.jackson.core
jackson-annotations
+
+ com.fasterxml.jackson.module
+ jackson-module-jsonSchema
+
io.vavr
vavr
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 5f308a1c4..a0249b382 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
@@ -282,6 +282,30 @@ public OpenAiChatCompletionRequest withToolChoice(@Nonnull final OpenAiToolChoic
return this.withToolChoice(choice.toolChoice);
}
+ /**
+ * Sets the tools to be used in the request with convenience class {@code OpenAiTool}.
+ *
+ * @param tools the list of tools to be used
+ * @return a new OpenAiChatCompletionRequest instance with the specified tools
+ * @throws IllegalArgumentException if the tool type is not supported
+ * @since 1.7.0
+ */
+ @Nonnull
+ public OpenAiChatCompletionRequest withOpenAiTools(@Nonnull final List tools) {
+ return this.withTools(
+ tools.stream()
+ .map(
+ tool -> {
+ if (tool instanceof OpenAiFunctionTool) {
+ return ((OpenAiFunctionTool) tool).createChatCompletionTool();
+ } else {
+ throw new IllegalArgumentException(
+ "Unsupported tool type: " + tool.getClass().getName());
+ }
+ })
+ .toList());
+ }
+
/**
* Converts the request to a generated model class CreateChatCompletionRequest.
*
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..2801f536d 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,12 @@
package com.sap.ai.sdk.foundationmodels.openai;
+import static com.sap.ai.sdk.foundationmodels.openai.OpenAiUtils.getOpenAiObjectMapper;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.annotations.Beta;
+import java.lang.reflect.Type;
+import java.util.Map;
import javax.annotation.Nonnull;
import lombok.AllArgsConstructor;
import lombok.Value;
@@ -22,4 +28,50 @@ public class OpenAiFunctionCall implements OpenAiToolCall {
/** The arguments for the function call, encoded as a JSON string. */
@Nonnull String arguments;
+
+ /**
+ * Parses the arguments, encoded as a JSON string, into a {@code Map}.
+ *
+ * @return a map of the arguments
+ * @throws IllegalArgumentException if parsing fails
+ * @since 1.7.0
+ */
+ @Nonnull
+ public Map getArgumentsAsMap() throws IllegalArgumentException {
+ return parseArguments(new TypeReference<>() {});
+ }
+
+ /**
+ * Parses the arguments, encoded as a JSON string, into an object of type expected by a function
+ * tool.
+ *
+ * @param tool the function tool the arguments are for
+ * @return the parsed arguments as an object
+ * @param the type of object accepted by the function tool
+ * @throws IllegalArgumentException if parsing arguments fails
+ * @since 1.7.0
+ */
+ @Nonnull
+ public T getArgumentsAsObject(@Nonnull final OpenAiFunctionTool tool)
+ throws IllegalArgumentException {
+ final var typeRef =
+ new TypeReference() {
+ @Override
+ public Type getType() {
+ return tool.getRequestModel();
+ }
+ };
+ return parseArguments(typeRef);
+ }
+
+ @Nonnull
+ private T parseArguments(@Nonnull final TypeReference typeReference)
+ throws IllegalArgumentException {
+ try {
+ return getOpenAiObjectMapper().readValue(getArguments(), typeReference);
+ } catch (JsonProcessingException e) {
+ throw new IllegalArgumentException(
+ "Failed to parse JSON string to class " + typeReference.getType(), e);
+ }
+ }
}
diff --git a/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiFunctionTool.java b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiFunctionTool.java
new file mode 100644
index 000000000..9d8d61cb5
--- /dev/null
+++ b/foundation-models/openai/src/main/java/com/sap/ai/sdk/foundationmodels/openai/OpenAiFunctionTool.java
@@ -0,0 +1,83 @@
+package com.sap.ai.sdk.foundationmodels.openai;
+
+import static com.sap.ai.sdk.foundationmodels.openai.generated.model.ChatCompletionTool.TypeEnum.FUNCTION;
+
+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.JsonSchema;
+import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;
+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.Map;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Value;
+import lombok.With;
+
+/**
+ * Represents an OpenAI function tool that can be used to define a function call in an OpenAI Chat
+ * Completion request. This tool generates a JSON schema based on the provided class representing
+ * the function's request structure.
+ *
+ * @see OpenAI Function
+ * @since 1.7.0
+ */
+@Beta
+@Value
+@With
+@Getter(AccessLevel.PACKAGE)
+@AllArgsConstructor(access = AccessLevel.PRIVATE)
+public class OpenAiFunctionTool implements OpenAiTool {
+
+ /** The name of the function. */
+ @Nonnull String name;
+
+ /** The model class for function request. */
+ @Nonnull Class> requestModel;
+
+ /** An optional description of the function. */
+ @Nullable String description;
+
+ /** An optional flag indicating whether the function parameters should be treated strictly. */
+ @Nullable Boolean strict;
+
+ /**
+ * Constructs an {@code OpenAiFunctionTool} with the specified name and a model class that
+ * captures the request to the function.
+ *
+ * @param name the name of the function
+ * @param requestModel the model class for the function request
+ * @param the type of the request model
+ */
+ public OpenAiFunctionTool(@Nonnull final String name, @Nonnull final Class requestModel) {
+ this(name, requestModel, null, null);
+ }
+
+ ChatCompletionTool createChatCompletionTool() {
+ final var objectMapper = new ObjectMapper();
+ JsonSchema schema = null;
+ try {
+ schema = new JsonSchemaGenerator(objectMapper).generateSchema(requestModel);
+ } catch (JsonMappingException e) {
+ throw new IllegalArgumentException(
+ "Could not generate schema for " + requestModel.getTypeName(), e);
+ }
+
+ schema.setId(null);
+ final var schemaMap =
+ objectMapper.convertValue(schema, new TypeReference