diff --git a/java/plugins/semantickernel-plugin-core/src/main/java/com/microsoft/semantickernel/plugins/TextPlugin.java b/java/plugins/semantickernel-plugin-core/src/main/java/com/microsoft/semantickernel/plugins/TextPlugin.java
index 0d39f95cbe..69ddf6791e 100644
--- a/java/plugins/semantickernel-plugin-core/src/main/java/com/microsoft/semantickernel/plugins/TextPlugin.java
+++ b/java/plugins/semantickernel-plugin-core/src/main/java/com/microsoft/semantickernel/plugins/TextPlugin.java
@@ -44,4 +44,19 @@ public class TextPlugin {
name = "input") String input) {
return input.toLowerCase(Locale.ROOT);
}
+
+
+ ///
+ /// Concatenate two strings into one
+ ///
+ /// First input to concatenate with
+ /// Second input to concatenate with
+ /// Concatenation result from both inputs.
+ @DefineKernelFunction(description = "Concat two strings into one.", name = "Concat")
+ public String concat(
+ @KernelFunctionParameter(description = "First input to concatenate with", name = "input") String input,
+ @KernelFunctionParameter(description = "Second input to concatenate with", name = "input2") String input2) {
+ return (input + input2);
+ }
+
}
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example05_InlineFunctionDefinition.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example05_InlineFunctionDefinition.java
index 30284af396..d8dd049d6a 100644
--- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example05_InlineFunctionDefinition.java
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example05_InlineFunctionDefinition.java
@@ -6,7 +6,6 @@ import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
-import com.microsoft.semantickernel.DefaultKernel;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
@@ -21,20 +20,21 @@ import java.time.format.DateTimeFormatter;
public class Example05_InlineFunctionDefinition {
- private static final boolean USE_AZURE_CLIENT = Boolean.parseBoolean(
- System.getenv("USE_AZURE_CLIENT"));
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
+ private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
- // Only required if USE_AZURE_CLIENT is true
+ // Only required if AZURE_CLIENT_KEY is set
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "text-davinci-003");
public static void main(String[] args) throws ConfigurationException {
OpenAIAsyncClient client;
- if (USE_AZURE_CLIENT) {
+ if (AZURE_CLIENT_KEY != null) {
client = new OpenAIClientBuilder()
- .credential(new AzureKeyCredential(CLIENT_KEY))
+ .credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
.endpoint(CLIENT_ENDPOINT)
.buildAsyncClient();
} else {
@@ -45,7 +45,7 @@ public class Example05_InlineFunctionDefinition {
TextGenerationService textGenerationService = TextGenerationService.builder()
.withOpenAIAsyncClient(client)
- .withModelId("text-davinci-003")
+ .withModelId(MODEL_ID)
.build();
Kernel kernel = Kernel.builder()
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example06_TemplateLanguage.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example06_TemplateLanguage.java
index 7aa50a5cda..79aa025f58 100644
--- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example06_TemplateLanguage.java
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example06_TemplateLanguage.java
@@ -4,7 +4,6 @@ import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
-import com.microsoft.semantickernel.DefaultKernel;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
@@ -19,12 +18,13 @@ import com.microsoft.semantickernel.textcompletion.TextGenerationService;
public class Example06_TemplateLanguage {
- private static final boolean USE_AZURE_CLIENT = Boolean.parseBoolean(
- System.getenv("USE_AZURE_CLIENT"));
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
+ private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
- // Only required if USE_AZURE_CLIENT is true
+ // Only required if AZURE_CLIENT_KEY is set
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "text-davinci-003");
public static class Time {
@@ -45,9 +45,9 @@ public class Example06_TemplateLanguage {
OpenAIAsyncClient client;
- if (USE_AZURE_CLIENT) {
+ if (AZURE_CLIENT_KEY != null) {
client = new OpenAIClientBuilder()
- .credential(new AzureKeyCredential(CLIENT_KEY))
+ .credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
.endpoint(CLIENT_ENDPOINT)
.buildAsyncClient();
} else {
@@ -57,9 +57,9 @@ public class Example06_TemplateLanguage {
}
TextGenerationService textGenerationService = OpenAITextGenerationService.builder()
- .withOpenAIAsyncClient(client)
- .withModelId("text-davinci-003")
- .build();
+ .withOpenAIAsyncClient(client)
+ .withModelId(MODEL_ID)
+ .build();
Kernel kernel = Kernel.builder()
.withDefaultAIService(TextGenerationService.class, textGenerationService)
@@ -85,10 +85,8 @@ public class Example06_TemplateLanguage {
// This allows to see the prompt before it's sent to OpenAI
System.out.println("--- Rendered Prompt");
- var promptTemplateFactory = new KernelPromptTemplateFactory();
-
- var promptTemplate = promptTemplateFactory.tryCreate(
- new PromptTemplateConfig(functionDefinition));
+ var promptTemplate = new KernelPromptTemplateFactory()
+ .tryCreate(new PromptTemplateConfig(functionDefinition));
var renderedPrompt = promptTemplate.renderAsync(kernel, null).block();
System.out.println(renderedPrompt);
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example08_RetryHandler.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example08_RetryHandler.java
index 158e5bc54a..630c215181 100644
--- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example08_RetryHandler.java
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example08_RetryHandler.java
@@ -14,7 +14,8 @@ import com.microsoft.semantickernel.textcompletion.TextGenerationService;
import java.time.Duration;
public class Example08_RetryHandler {
-
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "text-davinci-003");
public static void main(String[] args) throws ConfigurationException {
// Create a Kernel with the HttpClient
RetryOptions retryOptions = new RetryOptions(new ExponentialBackoffOptions()
@@ -30,7 +31,7 @@ public class Example08_RetryHandler {
TextGenerationService textGenerationService = TextGenerationService.builder()
.withOpenAIAsyncClient(client)
- .withModelId("text-davinci-003")
+ .withModelId(MODEL_ID)
.build();
Kernel kernel = Kernel.builder()
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example09_FunctionTypes.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example09_FunctionTypes.java
index fa69a39119..94c74d2ffa 100644
--- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example09_FunctionTypes.java
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example09_FunctionTypes.java
@@ -6,7 +6,6 @@ import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
-import com.microsoft.semantickernel.DefaultKernel;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
@@ -29,12 +28,13 @@ import reactor.core.publisher.Mono;
public class Example09_FunctionTypes {
- private static final boolean USE_AZURE_CLIENT = Boolean.parseBoolean(
- System.getenv("USE_AZURE_CLIENT"));
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
+ private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
- // Only required if USE_AZURE_CLIENT is true
+ // Only required if AZURE_CLIENT_KEY is set
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "text-davinci-003");
private static class DateTimeContextVariableTypeConverter extends
@@ -72,21 +72,21 @@ public class Example09_FunctionTypes {
OpenAIAsyncClient client;
- if (USE_AZURE_CLIENT) {
+ if (AZURE_CLIENT_KEY != null) {
client = new OpenAIClientBuilder()
- .credential(new AzureKeyCredential(CLIENT_KEY))
- .endpoint(CLIENT_ENDPOINT)
- .buildAsyncClient();
+ .credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
+ .endpoint(CLIENT_ENDPOINT)
+ .buildAsyncClient();
} else {
client = new OpenAIClientBuilder()
- .credential(new KeyCredential(CLIENT_KEY))
- .buildAsyncClient();
+ .credential(new KeyCredential(CLIENT_KEY))
+ .buildAsyncClient();
}
TextGenerationService textGenerationService = OpenAITextGenerationService.builder()
- .withOpenAIAsyncClient(client)
- .withModelId("text-davinci-003")
- .build();
+ .withOpenAIAsyncClient(client)
+ .withModelId(MODEL_ID)
+ .build();
// Load native plugin into the kernel function collection, sharing its functions with prompt templates
KernelPlugin plugin = KernelPluginFactory
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example10_DescribeAllPluginsAndFunctions.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example10_DescribeAllPluginsAndFunctions.java
index 5082c849f2..f3d0aa3b21 100644
--- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example10_DescribeAllPluginsAndFunctions.java
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example10_DescribeAllPluginsAndFunctions.java
@@ -4,7 +4,6 @@ import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
-import com.microsoft.semantickernel.DefaultKernel;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService;
import com.microsoft.semantickernel.orchestration.KernelFunction;
@@ -21,12 +20,14 @@ import java.util.Locale;
public class Example10_DescribeAllPluginsAndFunctions {
- private static final boolean USE_AZURE_CLIENT = Boolean.parseBoolean(
- System.getenv("USE_AZURE_CLIENT"));
- private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
- // Only required if USE_AZURE_CLIENT is true
+ private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
+ private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
+
+ // Only required if AZURE_CLIENT_KEY is set
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "text-davinci-003");
public static class StaticTextPlugin {
@@ -70,27 +71,25 @@ public class Example10_DescribeAllPluginsAndFunctions {
/// See the end of the file for a sample of what the output looks like.
///
public static void main(String[] args) {
- TextGenerationService textGenerationService;
+ OpenAIAsyncClient client;
- if (USE_AZURE_CLIENT) {
- OpenAIAsyncClient client = new OpenAIClientBuilder()
- .credential(new AzureKeyCredential(CLIENT_KEY))
+ if (AZURE_CLIENT_KEY != null) {
+ client = new OpenAIClientBuilder()
+ .credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
.endpoint(CLIENT_ENDPOINT)
.buildAsyncClient();
- textGenerationService = OpenAITextGenerationService.builder()
- .withOpenAIAsyncClient(client)
- .withModelId("text-davinci-003")
- .build();
} else {
- OpenAIAsyncClient client = new OpenAIClientBuilder()
+ client = new OpenAIClientBuilder()
.credential(new KeyCredential(CLIENT_KEY))
.buildAsyncClient();
-
- // TODO: Add support for OpenAI API
- textGenerationService = null;
}
+ TextGenerationService textGenerationService = OpenAITextGenerationService.builder()
+ .withOpenAIAsyncClient(client)
+ .withModelId(MODEL_ID)
+ .build();
+
Kernel kernel = Kernel.builder()
.withDefaultAIService(TextGenerationService.class, textGenerationService)
.build();
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example13_ConversationSummaryPlugin.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example13_ConversationSummaryPlugin.java
index d4d651995d..c9edd73ea7 100644
--- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example13_ConversationSummaryPlugin.java
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example13_ConversationSummaryPlugin.java
@@ -5,7 +5,6 @@ import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
-import com.microsoft.semantickernel.DefaultKernel;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
@@ -26,12 +25,13 @@ import reactor.core.publisher.Mono;
*/
public class Example13_ConversationSummaryPlugin {
- private static final boolean USE_AZURE_CLIENT = Boolean.parseBoolean(
- System.getenv("USE_AZURE_CLIENT"));
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
+ private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
- // Only required if USE_AZURE_CLIENT is true
+ // Only required if AZURE_CLIENT_KEY is set
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "text-davinci-003");
private static final String ChatTranscript =
@@ -219,27 +219,25 @@ public class Example13_ConversationSummaryPlugin {
}
private static Kernel initializeKernel() {
- TextGenerationService textGenerationService;
+ OpenAIAsyncClient client;
- if (USE_AZURE_CLIENT) {
- OpenAIAsyncClient client = new OpenAIClientBuilder()
- .credential(new AzureKeyCredential(CLIENT_KEY))
+ if (AZURE_CLIENT_KEY != null) {
+ client = new OpenAIClientBuilder()
+ .credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
.endpoint(CLIENT_ENDPOINT)
.buildAsyncClient();
- textGenerationService = OpenAITextGenerationService.builder()
- .withOpenAIAsyncClient(client)
- .withModelId("text-davinci-003")
- .build();
} else {
- OpenAIAsyncClient client = new OpenAIClientBuilder()
+ client = new OpenAIClientBuilder()
.credential(new KeyCredential(CLIENT_KEY))
.buildAsyncClient();
-
- // TODO: Add support for OpenAI API
- textGenerationService = null;
}
+ TextGenerationService textGenerationService = OpenAITextGenerationService.builder()
+ .withOpenAIAsyncClient(client)
+ .withModelId(MODEL_ID)
+ .build();
+
return Kernel.builder()
.withDefaultAIService(TextGenerationService.class, textGenerationService)
.build();
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example17_ChatGPT.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example17_ChatGPT.java
index 251d0114a6..8f9efb6fa1 100644
--- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example17_ChatGPT.java
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example17_ChatGPT.java
@@ -10,33 +10,35 @@ import com.microsoft.semantickernel.chatcompletion.ChatHistory;
public class Example17_ChatGPT {
- private static final boolean USE_AZURE_CLIENT = Boolean.parseBoolean(
- System.getenv("USE_AZURE_CLIENT"));
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
+ private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
- // Only required if USE_AZURE_CLIENT is true
+ // Only required if AZURE_CLIENT_KEY is set
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "gpt-35-turbo");
public static void main(String[] args) {
System.out.println("======== Open AI - ChatGPT ========");
OpenAIAsyncClient client;
- if (USE_AZURE_CLIENT) {
+ if (AZURE_CLIENT_KEY != null) {
client = new OpenAIClientBuilder()
- .credential(new AzureKeyCredential(CLIENT_KEY))
- .endpoint(CLIENT_ENDPOINT)
- .buildAsyncClient();
+ .credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
+ .endpoint(CLIENT_ENDPOINT)
+ .buildAsyncClient();
+
} else {
client = new OpenAIClientBuilder()
- .credential(new KeyCredential(CLIENT_KEY))
- .buildAsyncClient();
+ .credential(new KeyCredential(CLIENT_KEY))
+ .buildAsyncClient();
}
ChatCompletionService chatGPT = OpenAIChatCompletion.builder()
- .withModelId("gpt-35-turbo")
- .withOpenAIAsyncClient(client)
- .build();
+ .withModelId(MODEL_ID)
+ .withOpenAIAsyncClient(client)
+ .build();
System.out.println("Chat content:");
System.out.println("------------------------");
@@ -50,7 +52,8 @@ public class Example17_ChatGPT {
GPTReply(chatGPT, chatHistory);
messageOutput(chatHistory);
- chatHistory.addUserMessage("I love history and philosophy, I'd like to learn something new about Greece, any suggestion");
+ chatHistory.addUserMessage(
+ "I love history and philosophy, I'd like to learn something new about Greece, any suggestion");
messageOutput(chatHistory);
GPTReply(chatGPT, chatHistory);
@@ -65,7 +68,7 @@ public class Example17_ChatGPT {
private static void GPTReply(ChatCompletionService chatGPT, ChatHistory chatHistory) {
var reply = chatGPT.getChatMessageContentsAsync(chatHistory, null, null)
- .block();
+ .block();
StringBuilder message = new StringBuilder();
reply.forEach(chatMessageContent -> message.append(chatMessageContent.getContent()));
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example26_AADAuth.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example26_AADAuth.java
index 9f973fe004..4dcb26eea2 100644
--- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example26_AADAuth.java
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example26_AADAuth.java
@@ -12,6 +12,8 @@ import com.microsoft.semantickernel.exceptions.ConfigurationException;
public class Example26_AADAuth {
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "gpt-35-turbo");
public static void main(String[] args) throws ConfigurationException {
@@ -25,7 +27,7 @@ public class Example26_AADAuth {
ChatCompletionService chatService = ChatCompletionService.builder()
.withOpenAIAsyncClient(client)
- .withModelId("gpt-35-turbo-2")
+ .withModelId(MODEL_ID)
.build();
Kernel kernel = Kernel.builder()
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example27_PromptFunctionsUsingChatGPT.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example27_PromptFunctionsUsingChatGPT.java
index e330b58a76..50f3c7c58f 100644
--- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example27_PromptFunctionsUsingChatGPT.java
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example27_PromptFunctionsUsingChatGPT.java
@@ -13,22 +13,24 @@ import com.microsoft.semantickernel.plugin.KernelFunctionFactory;
public class Example27_PromptFunctionsUsingChatGPT {
- private static final boolean USE_AZURE_CLIENT = Boolean.parseBoolean(
- System.getenv("USE_AZURE_CLIENT"));
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
+ private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
- // Only required if USE_AZURE_CLIENT is true
+ // Only required if AZURE_CLIENT_KEY is set
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "gpt-35-turbo");
public static void main(String[] args) {
OpenAIAsyncClient client;
- if (USE_AZURE_CLIENT) {
+ if (AZURE_CLIENT_KEY != null) {
client = new OpenAIClientBuilder()
- .credential(new AzureKeyCredential(CLIENT_KEY))
+ .credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
.endpoint(CLIENT_ENDPOINT)
.buildAsyncClient();
+
} else {
client = new OpenAIClientBuilder()
.credential(new KeyCredential(CLIENT_KEY))
@@ -38,7 +40,7 @@ public class Example27_PromptFunctionsUsingChatGPT {
ChatCompletionService openAIChatCompletion = ChatCompletionService.builder()
.withOpenAIAsyncClient(client)
- .withModelId("gpt-35-turbo-2")
+ .withModelId(MODEL_ID)
.build();
Kernel kernel = Kernel.builder()
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example33_StreamingChat.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example33_StreamingChat.java
index 943e53e5f5..d91f6ee622 100644
--- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example33_StreamingChat.java
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example33_StreamingChat.java
@@ -13,31 +13,34 @@ import com.microsoft.semantickernel.chatcompletion.StreamingChatMessageContent;
public class Example33_StreamingChat {
- private static final boolean USE_AZURE_CLIENT = Boolean.parseBoolean(
- System.getenv("USE_AZURE_CLIENT"));
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
+ private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
- // Only required if USE_AZURE_CLIENT is true
+ // Only required if AZURE_CLIENT_KEY is set
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "gpt-35-turbo");
+
public static void main(String[] args) {
System.out.println("======== Open AI - ChatGPT Streaming ========");
OpenAIAsyncClient client;
- if (USE_AZURE_CLIENT) {
+ if (AZURE_CLIENT_KEY != null) {
client = new OpenAIClientBuilder()
- .credential(new AzureKeyCredential(CLIENT_KEY))
- .endpoint(CLIENT_ENDPOINT)
- .buildAsyncClient();
+ .credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
+ .endpoint(CLIENT_ENDPOINT)
+ .buildAsyncClient();
+
} else {
client = new OpenAIClientBuilder()
- .credential(new KeyCredential(CLIENT_KEY))
- .buildAsyncClient();
+ .credential(new KeyCredential(CLIENT_KEY))
+ .buildAsyncClient();
}
ChatCompletionService chatGPT = OpenAIChatCompletion.builder()
- .withModelId("gpt-35-turbo")
+ .withModelId(MODEL_ID)
.withOpenAIAsyncClient(client)
.build();
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example55_TextChunker.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example55_TextChunker.java
new file mode 100644
index 0000000000..e2c0cec75b
--- /dev/null
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example55_TextChunker.java
@@ -0,0 +1,54 @@
+package com.microsoft.semantickernel.samples.syntaxexamples;
+
+import com.microsoft.semantickernel.text.TextChunker;
+import java.util.List;
+
+public class Example55_TextChunker {
+
+ private static final String text = """
+ The city of Venice, located in the northeastern part of Italy,
+ is renowned for its unique geographical features. Built on more than 100 small islands in a lagoon in the
+ Adriatic Sea, it has no roads, just canals including the Grand Canal thoroughfare lined with Renaissance and
+ Gothic palaces. The central square, Piazza San Marco, contains St. Mark's Basilica, which is tiled with Byzantine
+ mosaics, and the Campanile bell tower offering views of the city's red roofs.
+
+ The Amazon Rainforest, also known as Amazonia, is a moist broadleaf tropical rainforest in the Amazon biome that
+ covers most of the Amazon basin of South America. This basin encompasses 7 million square kilometers, of which
+ 5.5 million square kilometers are covered by the rainforest. This region includes territory belonging to nine nations
+ and 3.4 million square kilometers of uncontacted tribes. The Amazon represents over half of the planet's remaining
+ rainforests and comprises the largest and most biodiverse tract of tropical rainforest in the world.
+
+ The Great Barrier Reef is the world's largest coral reef system composed of over 2,900 individual reefs and 900 islands
+ stretching for over 2,300 kilometers over an area of approximately 344,400 square kilometers. The reef is located in the
+ Coral Sea, off the coast of Queensland, Australia. The Great Barrier Reef can be seen from outer space and is the world's
+ biggest single structure made by living organisms. This reef structure is composed of and built by billions of tiny organisms,
+ known as coral polyps.
+ """.stripIndent();
+
+ public static void main(String[] args) {
+ RunExample();
+
+ // TODO: This example should also demo using token counters, not supported in Java atm
+ }
+
+
+ private static void RunExample() {
+ System.out.println("=== Text chunking ===");
+
+ var lines = TextChunker.splitPlainTextLines(text, 40);
+ var paragraphs = TextChunker.splitPlainTextParagraphs(lines, 120);
+
+ writeParagraphsToConsole(paragraphs);
+ }
+
+ private static void writeParagraphsToConsole(List paragraphs) {
+ for (var i = 0; i < paragraphs.size(); i++) {
+ System.out.println(paragraphs.get(i));
+
+ if (i < paragraphs.size() - 1) {
+ System.out.println("------------------------");
+ }
+ }
+ }
+
+}
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example56_TemplateMethodFunctionsWithMultipleArguments.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example56_TemplateMethodFunctionsWithMultipleArguments.java
new file mode 100644
index 0000000000..d1c92248d3
--- /dev/null
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example56_TemplateMethodFunctionsWithMultipleArguments.java
@@ -0,0 +1,91 @@
+package com.microsoft.semantickernel.samples.syntaxexamples;
+
+import com.azure.ai.openai.OpenAIAsyncClient;
+import com.azure.ai.openai.OpenAIClientBuilder;
+import com.azure.core.credential.AzureKeyCredential;
+import com.azure.core.credential.KeyCredential;
+import com.microsoft.semantickernel.Kernel;
+import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
+import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
+import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
+import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
+import com.microsoft.semantickernel.plugin.KernelPluginFactory;
+import com.microsoft.semantickernel.samples.plugins.text.TextPlugin;
+import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
+import com.microsoft.semantickernel.semanticfunctions.KernelPromptTemplateFactory;
+import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
+
+public class Example56_TemplateMethodFunctionsWithMultipleArguments {
+
+ private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
+ private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
+
+ // Only required if AZURE_CLIENT_KEY is set
+ private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "gpt-35-turbo");
+
+ public static void main(String[] args) {
+
+ OpenAIAsyncClient client;
+
+ if (AZURE_CLIENT_KEY != null) {
+ client = new OpenAIClientBuilder()
+ .credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
+ .endpoint(CLIENT_ENDPOINT)
+ .buildAsyncClient();
+
+ } else {
+ client = new OpenAIClientBuilder()
+ .credential(new KeyCredential(CLIENT_KEY))
+ .buildAsyncClient();
+ }
+
+ ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder()
+ .withModelId(MODEL_ID)
+ .withOpenAIAsyncClient(client)
+ .build();
+
+ Kernel kernel = Kernel.builder()
+ .withDefaultAIService(ChatCompletionService.class, openAIChatCompletion)
+ .build();
+
+ System.out.println("======== TemplateMethodFunctionsWithMultipleArguments ========");
+
+ var arguments = KernelArguments.builder()
+ .withVariable("word2", " Potter")
+ .build();
+
+ // Load native plugin into the kernel function collection, sharing its functions with prompt templates
+ // Functions loaded here are available as "text.*"
+ kernel.getPlugins().add(KernelPluginFactory.createFromObject(new TextPlugin(), "text"));
+
+ // Prompt Function invoking text.Concat method function with named arguments input and input2 where input is a string and input2 is set to a variable from context called word2.
+ String functionDefinition = "Write a haiku about the following: {{text.Concat input='Harry' input2=$word2}}";
+
+ // This allows to see the prompt before it's sent to OpenAI
+ System.out.println("--- Rendered Prompt");
+ var promptTemplateFactory = new KernelPromptTemplateFactory();
+ var promptTemplate = promptTemplateFactory.tryCreate(
+ new PromptTemplateConfig(functionDefinition));
+ var renderedPrompt = promptTemplate.renderAsync(kernel, arguments).block();
+ System.out.println(renderedPrompt);
+
+ // Run the prompt / prompt function
+
+ var haiku = KernelFunctionFromPrompt
+ .builder()
+ .withTemplate(functionDefinition)
+ .withDefaultExecutionSettings(
+ PromptExecutionSettings.builder()
+ .withMaxTokens(100)
+ .build())
+ .build();
+
+ // Show the result
+ System.out.println("--- Prompt Function result");
+ var result = kernel.invokeAsync(haiku, arguments, String.class).block();
+ System.out.println(result.getValue());
+ }
+
+}
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example58_ConfigureExecutionSettings.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example58_ConfigureExecutionSettings.java
new file mode 100644
index 0000000000..fdc9d0d9a8
--- /dev/null
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example58_ConfigureExecutionSettings.java
@@ -0,0 +1,99 @@
+package com.microsoft.semantickernel.samples.syntaxexamples;
+
+import com.azure.ai.openai.OpenAIAsyncClient;
+import com.azure.ai.openai.OpenAIClientBuilder;
+import com.azure.core.credential.AzureKeyCredential;
+import com.azure.core.credential.KeyCredential;
+import com.microsoft.semantickernel.Kernel;
+import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
+import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
+import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
+import com.microsoft.semantickernel.plugin.KernelFunctionFactory;
+import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
+import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
+
+public class Example58_ConfigureExecutionSettings {
+
+ private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
+ private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
+
+ // Only required if AZURE_CLIENT_KEY is set
+ private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "gpt-35-turbo");
+
+ public static void main(String[] args) {
+ System.out.println("======== Example58_ConfigureExecutionSettings ========");
+
+ OpenAIAsyncClient client;
+
+ if (AZURE_CLIENT_KEY != null) {
+ client = new OpenAIClientBuilder()
+ .credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
+ .endpoint(CLIENT_ENDPOINT)
+ .buildAsyncClient();
+
+ } else {
+ client = new OpenAIClientBuilder()
+ .credential(new KeyCredential(CLIENT_KEY))
+ .buildAsyncClient();
+ }
+
+ ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder()
+ .withModelId(MODEL_ID)
+ .withOpenAIAsyncClient(client)
+ .build();
+
+ System.out.println("======== Using Chat GPT model for text generation ========");
+
+ var kernel = Kernel.builder()
+ .withDefaultAIService(ChatCompletionService.class, openAIChatCompletion)
+ .build();
+
+ var prompt = "Hello AI, what can you do for me?";
+
+ // Option 1:
+ // Invoke the prompt function and pass an OpenAI specific instance containing the execution settings
+ var result = kernel.invokeAsync(
+ KernelFunctionFromPrompt.builder()
+ .withTemplate(prompt)
+ .withDefaultExecutionSettings(
+ PromptExecutionSettings.builder()
+ .withMaxTokens(60)
+ .withTemperature(0.7)
+ .build()
+ ).build(),
+ null,
+ String.class
+ ).block();
+
+ System.out.println(result.getValue());
+
+ // Option 2:
+ // Load prompt template configuration including the execution settings from a JSON payload
+ // Create the prompt functions using the prompt template and the configuration (loaded in the previous step)
+ // Invoke the prompt function using the implicitly set execution settings
+ String configPayload = """
+ {
+ "schema": 1,
+ "name": "HelloAI",
+ "description": "Say hello to an AI",
+ "type": "completion",
+ "completion": {
+ "max_tokens": 256,
+ "temperature": 0.5,
+ "top_p": 0.0,
+ "presence_penalty": 0.0,
+ "frequency_penalty": 0.0
+ }
+ }""".stripIndent();
+
+ var promptConfig = PromptTemplateConfig.parseFromJson(configPayload);
+ promptConfig.setTemplate(prompt);
+
+ var func = KernelFunctionFactory.createFromPrompt(promptConfig, null);
+
+ result = kernel.invokeAsync(func, null, String.class).block();
+ System.out.println(result.getValue());
+ }
+}
diff --git a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example64_MultiplePromptTemplates.java b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example64_MultiplePromptTemplates.java
index d9f23179ca..dfc162c4be 100644
--- a/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example64_MultiplePromptTemplates.java
+++ b/java/samples/sample-code/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example64_MultiplePromptTemplates.java
@@ -14,70 +14,73 @@ import com.microsoft.semantickernel.semanticfunctions.HandlebarsPromptTemplateFa
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
import com.microsoft.semantickernel.semanticfunctions.KernelPromptTemplateFactory;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateFactory;
-
import java.util.List;
public class Example64_MultiplePromptTemplates {
- private static final boolean USE_AZURE_CLIENT = Boolean.parseBoolean(
- System.getenv("USE_AZURE_CLIENT"));
private static final String CLIENT_KEY = System.getenv("CLIENT_KEY");
+ private static final String AZURE_CLIENT_KEY = System.getenv("AZURE_CLIENT_KEY");
- // Only required if USE_AZURE_CLIENT is true
+ // Only required if AZURE_CLIENT_KEY is set
private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT");
+ private static final String MODEL_ID = System.getenv()
+ .getOrDefault("MODEL_ID", "gpt-35-turbo");
+
public static void main(String[] args) {
System.out.println("======== Example64_MultiplePromptTemplates ========");
OpenAIAsyncClient client;
- if (USE_AZURE_CLIENT) {
+ if (AZURE_CLIENT_KEY != null) {
client = new OpenAIClientBuilder()
- .credential(new AzureKeyCredential(CLIENT_KEY))
- .endpoint(CLIENT_ENDPOINT)
- .buildAsyncClient();
+ .credential(new AzureKeyCredential(AZURE_CLIENT_KEY))
+ .endpoint(CLIENT_ENDPOINT)
+ .buildAsyncClient();
+
} else {
client = new OpenAIClientBuilder()
- .credential(new KeyCredential(CLIENT_KEY))
- .buildAsyncClient();
+ .credential(new KeyCredential(CLIENT_KEY))
+ .buildAsyncClient();
}
- ChatCompletionService chatCompletion = OpenAIChatCompletion.builder()
- .withModelId("gpt-35-turbo")
- .withOpenAIAsyncClient(client)
- .build();
+ ChatCompletionService openAIChatCompletion = OpenAIChatCompletion.builder()
+ .withModelId(MODEL_ID)
+ .withOpenAIAsyncClient(client)
+ .build();
var kernel = new DefaultKernel.Builder()
- .withDefaultAIService(ChatCompletionService.class, chatCompletion)
- .build();
+ .withDefaultAIService(ChatCompletionService.class, openAIChatCompletion)
+ .build();
var templateFactory = new AggregatorPromptTemplateFactory(
- List.of(
- new KernelPromptTemplateFactory(),
- new HandlebarsPromptTemplateFactory()
- )
+ List.of(
+ new KernelPromptTemplateFactory(),
+ new HandlebarsPromptTemplateFactory()
+ )
);
runPrompt(kernel,
- "semantic-kernel",
- "Hello AI, my name is {{$name}}. What is the origin of my name?",
- templateFactory);
+ "semantic-kernel",
+ "Hello AI, my name is {{$name}}. What is the origin of my name?",
+ templateFactory);
runPrompt(kernel,
- "handlebars",
- "Hello AI, my name is {{name}}. What is the origin of my name?",
- templateFactory);
+ "handlebars",
+ "Hello AI, my name is {{name}}. What is the origin of my name?",
+ templateFactory);
}
- public static void runPrompt (Kernel kernel, String templateFormat, String prompt, PromptTemplateFactory templateFactory) {
+ public static void runPrompt(Kernel kernel, String templateFormat, String prompt,
+ PromptTemplateFactory templateFactory) {
var function = new KernelFunctionFromPrompt.Builder()
- .withTemplate(prompt)
- .withTemplateFormat(templateFormat)
- .withPromptTemplateFactory(templateFactory)
- .build();
+ .withTemplate(prompt)
+ .withTemplateFormat(templateFormat)
+ .withPromptTemplateFactory(templateFactory)
+ .build();
var arguments = KernelArguments.builder()
- .withVariable("name", "Bob")
- .build();
+ .withVariable("name", "Bob")
+ .build();
var result = kernel.invokeAsync(function, arguments, String.class).block();
System.out.println(result.getValue());
diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelFunctionFactory.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelFunctionFactory.java
index 135409a36c..b80314c547 100644
--- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelFunctionFactory.java
+++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelFunctionFactory.java
@@ -4,6 +4,9 @@ import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionFromMethod;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
+import com.microsoft.semantickernel.semanticfunctions.KernelPromptTemplateFactory;
+import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
+import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateFactory;
import java.lang.reflect.Method;
import java.util.HashMap;
@@ -103,6 +106,26 @@ public class KernelFunctionFactory {
promptTemplateFactory);
}
+ public static KernelFunction createFromPrompt(
+ PromptTemplateConfig promptConfig,
+ @Nullable PromptTemplateFactory promptTemplateFactory) {
+
+ if (promptTemplateFactory == null) {
+ promptTemplateFactory = new KernelPromptTemplateFactory();
+ }
+
+ return KernelFunctionFactory.create(promptTemplateFactory.tryCreate(promptConfig),
+ promptConfig);
+ }
+
+ public static KernelFunction create(
+ PromptTemplate promptTemplate,
+ PromptTemplateConfig promptConfig) {
+ return new KernelFunctionFromPrompt(
+ promptTemplate,
+ promptConfig);
+ }
+
private static Map createSettingsDictionary(
PromptExecutionSettings executionSettings) {
HashMap map = new HashMap<>();
diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java
index d4d0efd632..6d7ce3190b 100644
--- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java
+++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java
@@ -280,9 +280,9 @@ public class KernelPluginFactory {
try {
String config = getFileContents(configFileName, clazz);
- return new ObjectMapper().readValue(config, PromptTemplateConfig.class);
- } catch (IOException e) {
- if (e instanceof JsonMappingException) {
+ return PromptTemplateConfig.parseFromJson(config);
+ } catch (Exception e) {
+ if (e instanceof SKException) {
LOGGER.error("Failed to parse config file " + configFileName, e);
throw new SKException("Failed to parse config file " + configFileName, e);
diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelPromptTemplateFactory.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelPromptTemplateFactory.java
index 9ac3a195c8..93fb1d17aa 100644
--- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelPromptTemplateFactory.java
+++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelPromptTemplateFactory.java
@@ -1,21 +1,26 @@
package com.microsoft.semantickernel.semanticfunctions;
+import static com.microsoft.semantickernel.semanticfunctions.HandlebarsPromptTemplateFactory.HANDLEBARS_TEMPLATE_FORMAT;
+import static com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT;
+
import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplate;
import com.microsoft.semantickernel.templateengine.semantickernel.DefaultPromptTemplate;
-import reactor.util.annotation.NonNull;
-
import java.util.Locale;
-import static com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig.SEMANTIC_KERNEL_TEMPLATE_FORMAT;
-
public class KernelPromptTemplateFactory implements PromptTemplateFactory {
- public PromptTemplate tryCreate(@NonNull PromptTemplateConfig templateConfig) {
- if (templateConfig.getTemplateFormat() != null &&
- SEMANTIC_KERNEL_TEMPLATE_FORMAT.equals(templateConfig.getTemplateFormat().toLowerCase(Locale.ROOT))) {
+ public PromptTemplate tryCreate(PromptTemplateConfig templateConfig) {
+ if (templateConfig == null || templateConfig.getTemplateFormat() == null) {
return new DefaultPromptTemplate(templateConfig);
}
- throw new UnknownTemplateFormatException(templateConfig.getTemplateFormat());
+ switch (templateConfig.getTemplateFormat().toLowerCase(Locale.ROOT)) {
+ case SEMANTIC_KERNEL_TEMPLATE_FORMAT:
+ return new DefaultPromptTemplate(templateConfig);
+ case HANDLEBARS_TEMPLATE_FORMAT:
+ return new HandlebarsPromptTemplate(templateConfig);
+ default:
+ throw new UnknownTemplateFormatException(templateConfig.getTemplateFormat());
+ }
}
}
diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateConfig.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateConfig.java
index 97c4af832f..5e8fdcaf9d 100644
--- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateConfig.java
+++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplateConfig.java
@@ -2,7 +2,11 @@
package com.microsoft.semantickernel.semanticfunctions;
import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.microsoft.semantickernel.exceptions.SKException;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.plugin.KernelParameterMetadata;
import com.microsoft.semantickernel.plugin.KernelReturnParameterMetadata;
@@ -13,6 +17,7 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
+@JsonIgnoreProperties(ignoreUnknown = true)
public class PromptTemplateConfig {
public static final int CURRENT_SCHEMA = 1;
@@ -271,4 +276,12 @@ public class PromptTemplateConfig {
this.executionSettings = executionSettings;
}
+ public static PromptTemplateConfig parseFromJson(String json) throws SKException {
+ try {
+ return new ObjectMapper().readValue(json, PromptTemplateConfig.class);
+ } catch (JsonProcessingException e) {
+ throw new SKException("Unable to parse prompt template config", e);
+ }
+ }
+
}
diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/TemplateTokenizer.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/TemplateTokenizer.java
index 5d0e99653c..10baf9606f 100644
--- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/TemplateTokenizer.java
+++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/TemplateTokenizer.java
@@ -167,13 +167,6 @@ public class TemplateTokenizer {
break;
case FunctionId:
- if (codeBlocks.size() > 2) {
- throw new TemplateException(
- TemplateException.ErrorCodes.SYNTAX_ERROR,
- "Functions support only one parameter: "
- + contentWithoutDelimiters);
- }
-
blocks.add(new CodeBlock(codeBlocks, contentWithoutDelimiters));
break;
diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/blocks/CodeBlock.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/blocks/CodeBlock.java
index c4d6826722..51f4acaab8 100644
--- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/blocks/CodeBlock.java
+++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/blocks/CodeBlock.java
@@ -37,27 +37,44 @@ public final class CodeBlock extends Block implements CodeRendering {
return false;
}
- if (this.tokens.size() > 1) {
- if (this.tokens.get(0).getType() != BlockTypes.FunctionId) {
- LOGGER.error("Unexpected second token found: " + this.tokens.get(1).getContent());
- return false;
- }
-
- if (this.tokens.get(1).getType() != BlockTypes.Value
- && this.tokens.get(1).getType() != BlockTypes.Variable) {
- LOGGER.error("Functions support only one parameter");
- return false;
- }
+ if (this.tokens.size() > 0 && this.tokens.get(0).getType() == BlockTypes.NamedArg) {
+ LOGGER.error("Unexpected named argument found. Expected function name first.");
+ return false;
}
- if (this.tokens.size() > 2) {
- LOGGER.error("Unexpected second token found: " + this.tokens.get(1).getContent());
+ if (this.tokens.size() > 1 && !this.isValidFunctionCall()) {
return false;
}
return true;
}
+ private boolean isValidFunctionCall() {
+ if (this.tokens.get(0).getType() != BlockTypes.FunctionId) {
+ LOGGER.error("Unexpected second token found: " + tokens.get(1).getContent());
+ return false;
+ }
+
+ if (this.tokens.get(1).getType() != BlockTypes.Value &&
+ this.tokens.get(1).getType() != BlockTypes.Variable &&
+ this.tokens.get(1).getType() != BlockTypes.NamedArg) {
+ LOGGER.error(
+ "The first arg of a function must be a quoted string, variable or named argument");
+ return false;
+ }
+
+ for (int i = 2; i < this.tokens.size(); i++) {
+ if (this.tokens.get(i).getType() != BlockTypes.NamedArg) {
+ LOGGER.error(
+ "Functions only support named arguments after the first argument. Argument " + i
+ + " is not named.");
+ return false;
+ }
+ }
+
+ return true;
+ }
+
@Override
public Mono renderCodeAsync(Kernel kernel, @Nullable KernelArguments arguments) {
if (!this.isValid()) {
diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/blocks/NamedArgBlock.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/blocks/NamedArgBlock.java
index 86fbee71ef..4b914b9e2c 100644
--- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/blocks/NamedArgBlock.java
+++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/semantickernel/blocks/NamedArgBlock.java
@@ -2,13 +2,16 @@ package com.microsoft.semantickernel.templateengine.semantickernel.blocks;
import static com.microsoft.semantickernel.templateengine.semantickernel.blocks.BlockTypes.NamedArg;
-import com.microsoft.semantickernel.Todo;
import com.microsoft.semantickernel.Verify;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import javax.annotation.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class NamedArgBlock extends Block implements TextRendering {
+ private static final Logger LOGGER = LoggerFactory.getLogger(NamedArgBlock.class);
+
private final String name;
private final String value;
private final VarBlock argNameAsVarBlock;
@@ -49,7 +52,24 @@ public class NamedArgBlock extends Block implements TextRendering {
@Override
public boolean isValid() {
- throw new Todo();
+ if (Verify.isNullOrEmpty(this.name)) {
+ LOGGER.error("A named argument must have a name");
+ return false;
+ }
+
+ if (this.valBlock != null && !this.valBlock.isValid()) {
+ LOGGER.error("There was an issue with the named argument value for '" + name);
+ return false;
+ } else if (this.varBlock != null && !this.varBlock.isValid()) {
+ LOGGER.error("There was an issue with the named argument value for '" + name);
+ return false;
+ } else if (this.valBlock == null && this.varBlock == null) {
+ LOGGER.error("A named argument must have a value");
+ return false;
+ }
+
+ // Argument names share the same validation as variables
+ return this.argNameAsVarBlock.isValid();
}
@Nullable