Skip to content
6 changes: 3 additions & 3 deletions orchestration/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@
<properties>
<project.rootdir>${project.basedir}/../</project.rootdir>
<coverage.complexity>82%</coverage.complexity>
<coverage.line>94%</coverage.line>
<coverage.instruction>93%</coverage.instruction>
<coverage.branch>75%</coverage.branch>
<coverage.line>93%</coverage.line>
<coverage.instruction>92%</coverage.instruction>
<coverage.branch>77%</coverage.branch>
<coverage.method>94%</coverage.method>
<coverage.class>100%</coverage.class>
</properties>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ static PromptTemplatingModuleConfigPrompt toTemplateModuleConfig(
* In this case, the request will fail, since the templating module will try to resolve the parameter.
* To be fixed with https://github.tools.sap/AI/llm-orchestration/issues/662
*/

if (config instanceof TemplateRef) {
return config;
}
Expand Down Expand Up @@ -249,4 +250,25 @@ static CompletionPostRequest fromReferenceToCompletionPostRequest(
return request;
}
}

@Nonnull
static CompletionRequestConfiguration fromTemplateRefToCompletionPostRequest(
@Nonnull final OrchestrationModuleConfig configWithRef) {
final OrchestrationTemplateReference templateRef = configWithRef.getTemplateRef();
final var messageHistory =
templateRef.getMessagesHistory().stream().map(Message::createChatMessage).toList();
final var placeholders = templateRef.getTemplateParameters();

final OrchestrationModuleConfig inner =
configWithRef.withTemplateConfig(templateRef.toLowLevel());

val requestConfig =
OrchestrationConfig.create().modules(toModuleConfigs(inner)).stream(
configWithRef.getGlobalStreamOptions());

return CompletionRequestConfiguration.create()
.config(requestConfig)
.placeholderValues(placeholders)
.messagesHistory(messageHistory);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,24 @@ public OrchestrationChatResponse chatCompletionUsingReference(
return new OrchestrationChatResponse(response);
}

/**
* Generate a completion using a module configuration containing a template reference Per-request
* history and parameters must be set on the template reference via {@link
* OrchestrationTemplateReference#withMessageHistory} and {@link
* OrchestrationTemplateReference#withTemplateParameters}.
*
* @param config A module configuration wrapping an {@link OrchestrationTemplateReference}.
* @return The completion output.
* @since 1.26.0
*/
@Nonnull
public OrchestrationChatResponse chatCompletionUsingTemplateRef(
@Nonnull final OrchestrationModuleConfig config) {
val request = ConfigToRequestTransformer.fromTemplateRefToCompletionPostRequest(config);
val response = executeRequest(request);
return new OrchestrationChatResponse(response);
}

/**
* Perform a request to the orchestration service using a module configuration provided as JSON
* string. This can be useful when building a configuration in the AI Launchpad UI and exporting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ public class OrchestrationModuleConfig {
@Nullable
SAPDocumentTranslationOutput outputTranslationConfig;

@Nullable OrchestrationTemplateReference templateRef;

/** Configuration of optional streaming options for output filtering. */
@With(AccessLevel.NONE) // may be exposed to public in the future
@Getter(AccessLevel.PACKAGE)
Expand Down Expand Up @@ -304,6 +306,7 @@ OrchestrationModuleConfig withOutputFilteringStreamOptions(
this.groundingConfig,
this.inputTranslationConfig,
this.outputTranslationConfig,
this.templateRef,
outputFilteringStreamOptions,
this.globalStreamOptions);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
import com.sap.ai.sdk.orchestration.model.TemplateRefByID;
import com.sap.ai.sdk.orchestration.model.TemplateRefByScenarioNameVersion;
import com.sap.ai.sdk.orchestration.model.TemplateRefTemplateRef;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Value;
import lombok.With;

Expand All @@ -28,6 +31,46 @@ public class OrchestrationTemplateReference extends TemplateConfig {
/** The scope of the template reference. */
@With @Nonnull ScopeEnum scope;

@Getter(AccessLevel.PACKAGE)
@Nonnull
List<Message> messagesHistory;

@Getter(AccessLevel.PACKAGE)
@Nonnull
Map<String, String> templateParameters;

/** Build a template reference with scope only. */
OrchestrationTemplateReference(
@Nonnull final TemplateRefTemplateRef reference, @Nonnull final ScopeEnum scope) {
this(reference, scope, List.of(), Map.of());
}

/**
* Set the chat history.
*
* @param messagesHistory The chat history to set.
* @return A new instance with the specified chat history.
*/
@Nonnull
public OrchestrationTemplateReference withMessageHistory(
@Nonnull final List<Message> messagesHistory) {
return new OrchestrationTemplateReference(
reference, scope, messagesHistory, templateParameters);
}

/**
* Set the template parameters.
*
* @param templateParameters The template parameters to set.
* @return A new instance with the specified template parameters.
*/
@Nonnull
public OrchestrationTemplateReference withTemplateParameters(
@Nonnull final Map<String, String> templateParameters) {
return new OrchestrationTemplateReference(
reference, scope, messagesHistory, templateParameters);
}

/**
* Create a low-level representation of the template.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -695,13 +695,14 @@ public OrchestrationChatResponse templateFromPromptRegistryByIdTenant(
@Nonnull final String topic) {
final var llmWithImageSupportConfig = new OrchestrationModuleConfig().withLlmConfig(GPT_5_MINI);

val template = TemplateConfig.reference().byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16");
val configWithTemplate = llmWithImageSupportConfig.withTemplateConfig(template);

val inputParams = Map.of("language", "Italian", "input", topic);
val prompt = new OrchestrationPrompt(inputParams);
val template =
TemplateConfig.reference()
.byId("21cb1358-0bf1-4f43-870b-00f14d0f9f16")
.withTemplateParameters(inputParams);
val configWithTemplate = llmWithImageSupportConfig.withTemplateConfig(template);

return client.chatCompletion(prompt, configWithTemplate);
return client.chatCompletionUsingTemplateRef(configWithTemplate);
}

/**
Expand All @@ -720,16 +721,15 @@ public OrchestrationChatResponse templateFromPromptRegistryByIdResourceGroup(
final var clientWithResourceGroup =
client.withResourceGroup("ai-sdk-java-e2e", "orchestration");

val inputParams = Map.of("categories", "Finance, Tech, Sports", "inputExample", inputExample);
val template =
TemplateConfig.reference()
.byId("8bf72116-11ab-41bb-8933-8be56f59cb67")
.withScope(RESOURCE_GROUP);
.withScope(RESOURCE_GROUP)
.withTemplateParameters(inputParams);
val configWithTemplate = config.withTemplateConfig(template);

val inputParams = Map.of("categories", "Finance, Tech, Sports", "inputExample", inputExample);
val prompt = new OrchestrationPrompt(inputParams);

return clientWithResourceGroup.chatCompletion(prompt, configWithTemplate);
return clientWithResourceGroup.chatCompletionUsingTemplateRef(configWithTemplate);
}

/**
Expand All @@ -744,13 +744,16 @@ public OrchestrationChatResponse templateFromPromptRegistryByIdResourceGroup(
@Nonnull
public OrchestrationChatResponse templateFromPromptRegistryByScenarioTenant(
@Nonnull final String topic) {
val template = TemplateConfig.reference().byScenario("test").name("test").version("0.0.1");
val configWithTemplate = config.withTemplateConfig(template);

val inputParams = Map.of("language", "Italian", "input", topic);
val prompt = new OrchestrationPrompt(inputParams);
val template =
TemplateConfig.reference()
.byScenario("test")
.name("test")
.version("0.0.1")
.withTemplateParameters(inputParams);
val configWithTemplate = config.withTemplateConfig(template);

return client.chatCompletion(prompt, configWithTemplate);
return client.chatCompletionUsingTemplateRef(configWithTemplate);
}

/**
Expand All @@ -769,18 +772,17 @@ public OrchestrationChatResponse templateFromPromptRegistryByScenarioResourceGro
final var clientWithResourceGroup =
client.withResourceGroup("ai-sdk-java-e2e", "orchestration");

val inputParams = Map.of("categories", "Finance, Tech, Sports", "inputExample", inputExample);
val template =
TemplateConfig.reference()
.byScenario("categorization")
.name("example-prompt-template")
.version("0.0.1")
.withScope(RESOURCE_GROUP);
.withScope(RESOURCE_GROUP)
.withTemplateParameters(inputParams);
val configWithTemplate = config.withTemplateConfig(template);

val inputParams = Map.of("categories", "Finance, Tech, Sports", "inputExample", inputExample);
val prompt = new OrchestrationPrompt(inputParams);

return clientWithResourceGroup.chatCompletion(prompt, configWithTemplate);
return clientWithResourceGroup.chatCompletionUsingTemplateRef(configWithTemplate);
}

/**
Expand Down