-
Notifications
You must be signed in to change notification settings - Fork 15
feat: [Orchestration] Convenience for response format #341
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
b146cfd
1611a08
d7c5039
cec2591
1ff4d5a
79865aa
0520339
b9d5d9a
28f8c63
6eb21bd
9b1482d
b7824d0
5ee6cea
731972a
fbf4944
168bd71
7c79e3a
57cc75f
537f28a
403cf50
a4ceb8d
a21cb6b
ffcb22e
42d7d22
6fe5fe7
fea3bc0
b736fea
f633d90
18c5dfd
2f99bb8
81dd4ab
6d1b700
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| package com.sap.ai.sdk.orchestration; | ||
|
|
||
| import com.google.common.annotations.Beta; | ||
| import com.sap.ai.sdk.orchestration.model.FilteringModuleConfig; | ||
| import com.sap.ai.sdk.orchestration.model.GroundingModuleConfig; | ||
| import com.sap.ai.sdk.orchestration.model.InputFilteringConfig; | ||
|
|
@@ -211,4 +212,21 @@ public OrchestrationModuleConfig withGrounding( | |
| @Nonnull final GroundingProvider groundingProvider) { | ||
| return this.withGroundingConfig(groundingProvider.createConfig()); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a new configuration with the given template configuration as {@link TemplateConfig}. | ||
| * | ||
| * @link <a href="https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/templating">SAP | ||
| * AI Core: Orchestration - Templating</a> | ||
| * @param templateConfig The template configuration to use. | ||
| * @return A new configuration with the given template configuration. | ||
| * @since 1.4.0 | ||
| */ | ||
| @Tolerate | ||
Jonas-Isr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| @Nonnull | ||
| @Beta | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added |
||
| public OrchestrationModuleConfig withTemplateConfig( | ||
| @Nonnull final TemplateConfig templateConfig) { | ||
| return this.withTemplateConfig(templateConfig.toLowLevel()); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| package com.sap.ai.sdk.orchestration; | ||
|
|
||
| import com.google.common.annotations.Beta; | ||
| import com.sap.ai.sdk.orchestration.model.ChatCompletionTool; | ||
| import com.sap.ai.sdk.orchestration.model.ChatMessage; | ||
| import com.sap.ai.sdk.orchestration.model.ResponseFormatJsonObject; | ||
| import com.sap.ai.sdk.orchestration.model.ResponseFormatJsonSchema; | ||
| import com.sap.ai.sdk.orchestration.model.ResponseFormatJsonSchemaJsonSchema; | ||
| import com.sap.ai.sdk.orchestration.model.Template; | ||
| import com.sap.ai.sdk.orchestration.model.TemplateResponseFormat; | ||
| import com.sap.ai.sdk.orchestration.model.TemplatingModuleConfig; | ||
| import java.util.ArrayList; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import javax.annotation.Nonnull; | ||
| import javax.annotation.Nullable; | ||
| import lombok.AccessLevel; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.EqualsAndHashCode; | ||
| import lombok.NoArgsConstructor; | ||
| import lombok.Value; | ||
| import lombok.With; | ||
| import lombok.val; | ||
|
|
||
| /** | ||
| * A template to use in {@link OrchestrationModuleConfig}. | ||
| * | ||
| * @since 1.4.0 | ||
| */ | ||
| @EqualsAndHashCode(callSuper = true) | ||
| @Value | ||
| @With | ||
| @AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
| @NoArgsConstructor(force = true, access = AccessLevel.PACKAGE) | ||
| @Beta | ||
| public class OrchestrationTemplate extends TemplateConfig { | ||
| @Nullable List<ChatMessage> template; | ||
| @Nullable Map<String, String> defaults; | ||
|
|
||
| @With(AccessLevel.PRIVATE) | ||
| @Nullable | ||
| TemplateResponseFormat responseFormat; | ||
|
|
||
| @Nullable List<ChatCompletionTool> tools; | ||
|
|
||
| /** | ||
| * Create a low-level representation of the template. | ||
| * | ||
| * @return The low-level representation of the template. | ||
| */ | ||
| @Override | ||
| @Nonnull | ||
| protected TemplatingModuleConfig toLowLevel() { | ||
| final List<ChatMessage> template = this.template != null ? this.template : List.of(); | ||
| final Map<String, String> defaults = this.defaults != null ? this.defaults : new HashMap<>(); | ||
| final List<ChatCompletionTool> tools = this.tools != null ? this.tools : new ArrayList<>(); | ||
| return Template.create() | ||
| .template(template) | ||
| .defaults(defaults) | ||
| .responseFormat(responseFormat) | ||
| .tools(tools); | ||
| } | ||
|
|
||
| /** | ||
| * Set the response format to the given JSON schema. | ||
| * | ||
| * @param schema The JSON schema to use. | ||
| * @return The updated template. | ||
| */ | ||
| @Nonnull | ||
| public OrchestrationTemplate withJsonSchemaResponse(@Nonnull final ResponseJsonSchema schema) { | ||
| val responseFormatJsonSchema = | ||
| ResponseFormatJsonSchema.create() | ||
| .type(ResponseFormatJsonSchema.TypeEnum.JSON_SCHEMA) | ||
| .jsonSchema( | ||
| ResponseFormatJsonSchemaJsonSchema.create() | ||
| .name(schema.getName()) | ||
| .schema(schema.getSchemaMap()) | ||
| .strict(schema.getStrict()) | ||
| .description(schema.getDescription())); | ||
| return this.withResponseFormat(responseFormatJsonSchema); | ||
| } | ||
|
|
||
| /** | ||
| * Set the response format to JSON object. | ||
| * | ||
| * @return The updated template. | ||
| */ | ||
| @Nonnull | ||
| public OrchestrationTemplate withJsonResponse() { | ||
| val responseFormatJsonObject = | ||
| ResponseFormatJsonObject.create().type(ResponseFormatJsonObject.TypeEnum.JSON_OBJECT); | ||
| return this.withResponseFormat(responseFormatJsonObject); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package com.sap.ai.sdk.orchestration; | ||
|
|
||
| import com.google.common.annotations.Beta; | ||
| import com.sap.ai.sdk.orchestration.model.TemplateRef; | ||
| import com.sap.ai.sdk.orchestration.model.TemplateRefTemplateRef; | ||
| import com.sap.ai.sdk.orchestration.model.TemplatingModuleConfig; | ||
| import javax.annotation.Nonnull; | ||
| import lombok.AccessLevel; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.EqualsAndHashCode; | ||
| import lombok.Value; | ||
|
|
||
| /** | ||
| * A reference to a template to use in {@link OrchestrationModuleConfig}. | ||
| * | ||
| * @since 1.4.0 | ||
| */ | ||
| @EqualsAndHashCode(callSuper = true) | ||
| @Value | ||
Jonas-Isr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| @AllArgsConstructor(access = AccessLevel.PROTECTED) | ||
| @Beta | ||
| public class OrchestrationTemplateReference extends TemplateConfig { | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did not add tests for this class in |
||
| @Nonnull TemplateRefTemplateRef reference; | ||
|
|
||
| /** | ||
| * Create a low-level representation of the template. | ||
| * | ||
| * @return The low-level representation of the template. | ||
| */ | ||
| @Nonnull | ||
| @Override | ||
| protected TemplatingModuleConfig toLowLevel() { | ||
| return TemplateRef.create().templateRef(reference); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| package com.sap.ai.sdk.orchestration; | ||
|
|
||
| import com.fasterxml.jackson.core.type.TypeReference; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import com.github.victools.jsonschema.generator.Option; | ||
| import com.github.victools.jsonschema.generator.OptionPreset; | ||
| import com.github.victools.jsonschema.generator.SchemaGenerator; | ||
| import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder; | ||
| 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 java.lang.reflect.Type; | ||
| import java.util.Map; | ||
| import javax.annotation.Nonnull; | ||
| import javax.annotation.Nullable; | ||
| import lombok.AccessLevel; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Value; | ||
| import lombok.With; | ||
| import lombok.val; | ||
|
|
||
| /** | ||
| * The schema object to use for the response format parameter in {@link OrchestrationTemplate}. | ||
| * | ||
| * @since 1.4.0 | ||
| */ | ||
| @Value | ||
| @AllArgsConstructor(access = AccessLevel.PACKAGE) | ||
| @With | ||
| @Beta | ||
| public class ResponseJsonSchema { | ||
| @Nonnull Map<String, Object> schemaMap; | ||
| @Nonnull String name; | ||
| @Nullable String description; | ||
| @Nullable Boolean strict; | ||
|
|
||
| /** | ||
| * Create a new instance of {@link ResponseJsonSchema} with the given schema map and name. | ||
| * | ||
| * @param schemaMap The schema map | ||
| * @param name The name of the schema | ||
| * @return The new instance of {@link ResponseJsonSchema} | ||
| */ | ||
| @Nonnull | ||
| public static ResponseJsonSchema fromMap( | ||
| @Nonnull final Map<String, Object> schemaMap, @Nonnull final String name) { | ||
| return new ResponseJsonSchema(schemaMap, name, null, null); | ||
| } | ||
|
|
||
| /** | ||
| * Create a new instance of {@link ResponseJsonSchema} from a given class. | ||
| * | ||
| * @param classType The class to generate the schema from | ||
| * @return The new instance of {@link ResponseJsonSchema} | ||
| */ | ||
| @Nonnull | ||
| public static ResponseJsonSchema fromType(@Nonnull final Type classType) { | ||
| val module = | ||
| new JacksonModule( | ||
| JacksonOption.RESPECT_JSONPROPERTY_REQUIRED, JacksonOption.RESPECT_JSONPROPERTY_ORDER); | ||
| val generator = | ||
| new SchemaGenerator( | ||
| new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2020_12, OptionPreset.PLAIN_JSON) | ||
| .without(Option.SCHEMA_VERSION_INDICATOR) | ||
| .with(Option.FORBIDDEN_ADDITIONAL_PROPERTIES_BY_DEFAULT) | ||
| .with(module) | ||
| .build()); | ||
| val jsonSchema = generator.generateSchema(classType); | ||
| val mapper = new ObjectMapper(); | ||
| val schemaMap = mapper.convertValue(jsonSchema, new TypeReference<Map<String, Object>>() {}); | ||
| val schemaName = ((Class<?>) classType).getSimpleName() + "-Schema"; | ||
Jonas-Isr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return new ResponseJsonSchema(schemaMap, schemaName, null, null); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.