Java: InvocationContext API (#4790)

Roll prompt execution settings, kernel args, hooks, and return type into
an InvocationContext and add methods to Kernel and KernelFunction that
use an InvocationContext. The idea is that the invokeAsync methods that
take a KernelFunction, args and a return type are fine, but we don't
want to blow out the API with variations of invokeAsync for hooks, etc.
Also, prompt execution settings were in KernelArguments, which just
doesn't make sense. Now we can extend/add to the context as the need
arises without having to change the Kernel and KernelFunction API.
Sweet!
This commit is contained in:
David Grieve
2024-02-06 16:46:52 +00:00
committed by GitHub
parent 48e0b406cc
commit 52f2ef6588
86 changed files with 1689 additions and 1546 deletions
@@ -16,9 +16,11 @@ import com.azure.ai.openai.models.ChatRequestUserMessage;
import com.azure.ai.openai.models.ChatResponseMessage;
import com.azure.ai.openai.models.FunctionCall;
import com.azure.ai.openai.models.FunctionDefinition;
import com.azure.core.util.BinaryData;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.util.JSONPObject;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.AuthorRole;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
@@ -31,13 +33,16 @@ import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.hooks.PreChatCompletionEvent;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
import com.microsoft.semantickernel.orchestration.InvocationContext;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.ToolCallBehavior;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelParameterMetadata;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
@@ -90,61 +95,29 @@ public class OpenAIChatCompletion implements ChatCompletionService {
@Override
public Mono<List<ChatMessageContent>> getChatMessageContentsAsync(
ChatHistory chatHistory,
@Nullable
PromptExecutionSettings promptExecutionSettings,
@Nullable
Kernel kernel,
@Nullable
KernelHooks kernelHooks) {
@Nullable Kernel kernel,
@Nullable InvocationContext invocationContext) {
List<ChatRequestMessage> chatRequestMessages = getChatRequestMessages(chatHistory);
List<FunctionDefinition> functions = Collections.emptyList();
if (kernelHooks == null) {
kernelHooks = new KernelHooks();
}
List<FunctionDefinition> functions = kernel != null ? getFunctions(kernel) : Collections.emptyList();
return internalChatMessageContentsAsync(
chatRequestMessages,
functions,
promptExecutionSettings,
kernelHooks);
invocationContext);
}
@Override
public Mono<List<ChatMessageContent>> getChatMessageContentsAsync(
ChatHistory chatHistory,
@Nullable PromptExecutionSettings promptExecutionSettings,
@Nullable Kernel kernel) {
return getChatMessageContentsAsync(chatHistory, promptExecutionSettings, kernel, null);
}
@Override
public Mono<List<ChatMessageContent>> getChatMessageContentsAsync(
String prompt,
@Nullable
PromptExecutionSettings promptExecutionSettings,
Kernel kernel,
@Nullable
KernelHooks kernelHooks) {
@Nullable Kernel kernel,
@Nullable InvocationContext invocationContext) {
ParsedPrompt parsedPrompt = XMLPromptParser.parse(prompt);
if (kernelHooks == null) {
kernelHooks = new KernelHooks();
}
return internalChatMessageContentsAsync(
parsedPrompt.getChatRequestMessages(),
parsedPrompt.getFunctions(),
promptExecutionSettings,
kernelHooks);
}
@Override
public Mono<List<ChatMessageContent>> getChatMessageContentsAsync(String prompt,
PromptExecutionSettings promptExecutionSettings, Kernel kernel) {
return getChatMessageContentsAsync(prompt, promptExecutionSettings, kernel, null);
invocationContext);
}
@@ -152,14 +125,11 @@ public class OpenAIChatCompletion implements ChatCompletionService {
List<ChatRequestMessage> chatRequestMessages,
@Nullable
List<FunctionDefinition> functions,
@Nullable
PromptExecutionSettings promptExecutionSettings,
KernelHooks kernelHooks) {
@Nullable InvocationContext invocationContext) {
ChatCompletionsOptions options = getCompletionsOptions(this, chatRequestMessages, functions,
promptExecutionSettings);
ChatCompletionsOptions options = getCompletionsOptions(this, chatRequestMessages, functions, invocationContext);
Mono<List<ChatMessageContent>> results =
internalChatMessageContentsAsync(kernelHooks, options);
internalChatMessageContentsAsync(options, invocationContext);
return results
.flatMap(list -> {
@@ -175,15 +145,20 @@ public class OpenAIChatCompletion implements ChatCompletionService {
}
}
if (makeSecondCall) {
return internalChatMessageContentsAsync(kernelHooks, options);
return internalChatMessageContentsAsync(options, invocationContext);
}
return Mono.just(list);
});
}
private Mono<List<ChatMessageContent>> internalChatMessageContentsAsync(
KernelHooks kernelHooks,
ChatCompletionsOptions options) {
ChatCompletionsOptions options,
@Nullable InvocationContext invocationContext) {
KernelHooks kernelHooks =
invocationContext != null && invocationContext.getKernelHooks() != null
? invocationContext.getKernelHooks()
: new KernelHooks();
options = kernelHooks
.executeHooks(new PreChatCompletionEvent(options))
@@ -297,7 +272,7 @@ public class OpenAIChatCompletion implements ChatCompletionService {
return Mono.empty();
}
KernelArguments arguments = null;
KernelFunctionArguments arguments = null;
if (parameters != null) {
Map<String, ContextVariable<?>> variables = new HashMap<>();
parameters.fields().forEachRemaining(entry -> {
@@ -306,7 +281,7 @@ public class OpenAIChatCompletion implements ChatCompletionService {
ContextVariable<?> contextVariable = ContextVariable.of(paramValue);
variables.put(paramName, contextVariable);
});
arguments = KernelArguments.builder().withVariables(variables).build();
arguments = KernelFunctionArguments.builder().withVariables(variables).build();
}
ContextVariableType<String> variableType = ContextVariableTypes.getDefaultVariableTypeForClass(
String.class);
@@ -319,11 +294,15 @@ public class OpenAIChatCompletion implements ChatCompletionService {
@Nullable
List<FunctionDefinition> functions,
@Nullable
PromptExecutionSettings promptExecutionSettings) {
InvocationContext invocationContext) {
ChatCompletionsOptions options = new ChatCompletionsOptions(chatRequestMessages)
.setModel(chatCompletionService.getModelId());
PromptExecutionSettings promptExecutionSettings = invocationContext != null
? invocationContext.getPromptExecutionSettings()
: null;
if (promptExecutionSettings == null) {
return options;
}
@@ -335,9 +314,12 @@ public class OpenAIChatCompletion implements ChatCompletionService {
MAX_RESULTS_PER_PROMPT));
}
ToolCallBehavior toolCallBehavior = invocationContext != null
? invocationContext.getToolCallBehavior()
: null;
List<ChatCompletionsToolDefinition> toolDefinitions =
chatCompletionsToolDefinitions(promptExecutionSettings.getToolCallBehavior(),
functions);
chatCompletionsToolDefinitions(toolCallBehavior,functions);
if (toolDefinitions != null && !toolDefinitions.isEmpty()) {
options.setTools(toolDefinitions);
// TODO: options.setToolChoices(toolChoices);
@@ -387,6 +369,7 @@ public class OpenAIChatCompletion implements ChatCompletionService {
if (toolCallBehavior == null || !(toolCallBehavior.kernelFunctionsEnabled()
|| toolCallBehavior.autoInvokeEnabled())) {
// If tool calls are not explicitly enabled, then we don't need to send any tool definitions
return Collections.emptyList();
}
@@ -440,6 +423,76 @@ public class OpenAIChatCompletion implements ChatCompletionService {
}
private static List<FunctionDefinition> getFunctions(Kernel kernel) {
List<FunctionDefinition> functions = new ArrayList<>();
kernel.getPlugins().iterator().forEachRemaining(plugin -> {
plugin.iterator().forEachRemaining(function -> {
FunctionDefinition functionDefinition = toFunctionDefinition(function);
functions.add(functionDefinition);
});
});
return functions;
}
private static FunctionDefinition toFunctionDefinition(KernelFunction function) {
String name = String.format("%s-%s", function.getSkillName(), function.getName());
FunctionDefinition functionDefinition = new FunctionDefinition(name);
functionDefinition.setDescription(function.getDescription());
// Example JSON Schema:
// {
// "type": "function",
// "function": {
// "name": "get_current_weather",
// "description": "Get the current weather in a given location",
// "parameters": {
// "type": "object",
// "properties": {
// "location": {
// "type": "string",
// "description": "The city and state, e.g. San Francisco, CA",
// },
// "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
// },
// "required": ["location"],
// },
// },
//}
List<KernelParameterMetadata<?>> parameters = function.getMetadata().getParameters();
if (!parameters.isEmpty()) {
List<String> requiredParmeters = new ArrayList<>();
StringBuilder sb = new StringBuilder(
"{\"type\": \"object\", \"properties\": {");
parameters.forEach(parameter -> {
// make "param": {"type": "string", "description": "desc"},
sb.append(String.format("\"%s\": %s,", parameter.getName(), parameter.getDescription()));
if (parameter.isRequired()) {
requiredParmeters.add(parameter.getName());
}
});
// strip off trailing comma and close the properties object
sb.replace(sb.length() - 1, sb.length(), "}");
if (!requiredParmeters.isEmpty()) {
sb.append(", \"required\": [");
requiredParmeters.forEach(it -> {
sb.append(String.format("\"%s\",", it));
});
// strip off trailing comma and close the required array
sb.replace(sb.length() - 1, sb.length(), "]");
}
// close the object
sb.append("}");
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(sb.toString());
BinaryData binaryData = BinaryData.fromObject(jsonNode);
functionDefinition.setParameters(binaryData);
} catch (JsonProcessingException e) {
LOGGER.error("Failed to parse json", e);
}
}
return functionDefinition;
}
private interface ContentBuffer<T> {
void append(T content);
+2 -2
View File
@@ -53,7 +53,7 @@
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-connectors-ai-openai</artifactId>
<artifactId>semantickernel-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
@@ -189,4 +189,4 @@
</profiles>
</project>
</project>
@@ -2,7 +2,7 @@
package com.microsoft.semantickernel.syntaxexamples;
import com.microsoft.semantickernel.samples.plugins.text.TextPlugin;
import com.microsoft.semantickernel.plugins.text.TextPlugin;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -3,7 +3,8 @@ package com.microsoft.semantickernel.syntaxexamples;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.samples.syntaxexamples.Example03_Arguments.StaticTextPlugin;
@@ -24,16 +25,14 @@ public class Example03_ArgumentsTest {
KernelPlugin functionCollection =
KernelPluginFactory.createFromObject(new StaticTextPlugin(), "text");
KernelArguments arguments = KernelArguments.builder()
KernelFunctionArguments arguments = KernelFunctionArguments.builder()
.withInput("Today is: ")
.build()
.writableClone()
.setVariable("day", "Monday");
.withVariable("day", "Monday")
.build();
FunctionResult<String> resultValue = kernel.invokeAsync(
functionCollection.get("AppendDay"),
arguments,
String.class)
(KernelFunction<String>)functionCollection.<String>get("AppendDay"),
arguments)
.block();
Assertions.assertEquals("Today is: Monday", resultValue.getResult());
@@ -8,8 +8,9 @@ import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelFunctionFactory;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
import com.microsoft.semantickernel.textcompletion.TextGenerationService;
@@ -71,7 +72,7 @@ public class Example05_InlineFunctionDefinitionTest {
Event: {{$input}}
""".stripIndent();
var excuseFunction = new KernelFunctionFromPrompt.Builder()
var excuseFunction = new KernelFunctionFromPrompt.Builder<String>()
.withName("Excuse")
.withTemplate(promptTemplate)
.withDefaultExecutionSettings(
@@ -86,10 +87,9 @@ public class Example05_InlineFunctionDefinitionTest {
WireMockUtil.mockCompletionResponse("I missed the F1 final race", "a-response");
var result = kernel.invokeAsync(excuseFunction,
KernelArguments.builder()
KernelFunctionArguments.builder()
.withInput("I missed the F1 final race")
.build(),
String.class)
.build())
.block();
Assertions.assertEquals("a-response", result.getResult());
@@ -97,17 +97,16 @@ public class Example05_InlineFunctionDefinitionTest {
WireMockUtil.mockCompletionResponse("sorry I forgot your birthday", "a-response-2");
result = kernel.invokeAsync(excuseFunction,
KernelArguments.builder()
KernelFunctionArguments.builder()
.withInput("sorry I forgot your birthday")
.build(),
String.class)
.build())
.block();
Assertions.assertEquals("a-response-2", result.getResult());
WireMockUtil.mockCompletionResponse("Translate this date ", "a-response-3");
var fixedFunction = KernelFunctionFactory.createFromPrompt(
var fixedFunction = KernelFunctionFactory.<String>createFromPrompt(
"Translate this date " + DateTimeFormatter
.ISO_LOCAL_DATE
.withZone(ZoneOffset.UTC)
@@ -122,7 +121,7 @@ public class Example05_InlineFunctionDefinitionTest {
null);
FunctionResult<String> fixedFunctionResult = kernel
.invokeAsync(fixedFunction, null, String.class)
.invokeAsync(fixedFunction, null)
.block();
Assertions.assertEquals("a-response-3", fixedFunctionResult.getResult());
@@ -1,5 +1,5 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.samples.plugins.text;
package com.microsoft.semantickernel.plugins.text;
import com.microsoft.semantickernel.plugin.annotations.DefineKernelFunction;
import com.microsoft.semantickernel.plugin.annotations.KernelFunctionParameter;
-2
View File
@@ -89,7 +89,6 @@
<plugin>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-maven-plugin</artifactId>
<version>${maven.spotbugs-plugin.version}</version>
<configuration>
<skip>true</skip>
</configuration>
@@ -113,7 +112,6 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>run-sample</id>
@@ -1,15 +1,17 @@
package com.microsoft.semantickernel.samples.plugins;
import java.util.List;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.orchestration.contextvariables.DefaultKernelArguments;
import com.microsoft.semantickernel.plugin.KernelFunctionFactory;
import com.microsoft.semantickernel.plugin.annotations.DefineKernelFunction;
import com.microsoft.semantickernel.plugin.annotations.KernelFunctionParameter;
import com.microsoft.semantickernel.text.TextChunker;
import java.util.List;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -23,9 +25,9 @@ public class ConversationSummaryPlugin {
/// </summary>
private static final int MaxTokens = 1024;
private KernelFunction summarizeConversationFunction;
private KernelFunction conversationActionItemsFunction;
private KernelFunction conversationTopicsFunction;
private KernelFunction<String> summarizeConversationFunction;
private KernelFunction<String> conversationActionItemsFunction;
private KernelFunction<String> conversationTopicsFunction;
/// <summary>
/// Initializes a new instance of the <see cref="ConversationSummaryPlugin"/> class.
@@ -123,19 +125,18 @@ public class ConversationSummaryPlugin {
return processAsync(this.conversationTopicsFunction, input, kernel);
}
private static Mono<String> processAsync(KernelFunction func, String input, Kernel kernel) {
private static Mono<String> processAsync(KernelFunction<String> func, String input, Kernel kernel) {
List<String> lines = TextChunker.splitPlainTextLines(input, MaxTokens);
List<String> paragraphs = TextChunker.splitPlainTextParagraphs(lines, MaxTokens);
return Flux.fromIterable(paragraphs)
.concatMap(paragraph -> {
// The first parameter is the input text.
return func
.invokeAsync(kernel,
new DefaultKernelArguments.Builder()
.withInput(paragraph)
.build(),
ContextVariableTypes.getDefaultVariableTypeForClass(String.class));
return func.invokeAsync(kernel,
new KernelFunctionArguments.Builder()
.withInput(paragraph)
.build(),
ContextVariableTypes.getDefaultVariableTypeForClass(String.class));
})
.reduce("", (acc, next) -> {
return acc + "\n" + next.getResult();
@@ -1,6 +1,6 @@
package com.microsoft.semantickernel.samples.syntaxexamples;
import com.microsoft.semantickernel.samples.plugins.text.TextPlugin;
import com.microsoft.semantickernel.plugins.text.TextPlugin;
/**
* Demonstrates a native function from the {@code com.microsoft.semantickernel.coreskills} package.
@@ -1,14 +1,16 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.samples.syntaxexamples;
import java.util.Locale;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.plugin.annotations.DefineKernelFunction;
import com.microsoft.semantickernel.plugin.annotations.KernelFunctionParameter;
import java.util.Locale;
import reactor.core.publisher.Mono;
/**
@@ -50,16 +52,14 @@ public class Example03_Arguments {
KernelPlugin functionCollection =
KernelPluginFactory.createFromObject(new StaticTextPlugin(), "text");
KernelArguments arguments = KernelArguments.builder()
KernelFunctionArguments arguments = KernelFunctionArguments.builder()
.withInput("Today is: ")
.build()
.writableClone()
.setVariable("day", "Monday");
.withVariable("day", "Monday")
.build();
FunctionResult<String> resultValue = kernel.invokeAsync(
FunctionResult<?> resultValue = kernel.invokeAsync(
functionCollection.get("AppendDay"),
arguments,
String.class)
arguments)
.block();
System.out.println(resultValue.getResult());
@@ -10,7 +10,7 @@ import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.plugin.KernelFunctionFactory;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
import com.microsoft.semantickernel.textcompletion.TextGenerationService;
@@ -80,18 +80,16 @@ public class Example05_InlineFunctionDefinition {
.build();
var result = kernel.invokeAsync(excuseFunction,
KernelArguments.builder()
KernelFunctionArguments.builder()
.withInput("I missed the F1 final race")
.build(),
String.class)
.build())
.block();
System.out.println(result.getResult());
result = kernel.invokeAsync(excuseFunction,
KernelArguments.builder()
KernelFunctionArguments.builder()
.withInput("sorry I forgot your birthday")
.build(),
String.class)
.build())
.block();
System.out.println(result.getResult());
@@ -109,8 +107,8 @@ public class Example05_InlineFunctionDefinition {
null,
null);
FunctionResult<String> fixedFunctionResult = kernel
.invokeAsync(fixedFunction, null, String.class)
FunctionResult<?> fixedFunctionResult = kernel
.invokeAsync(fixedFunction, null)
.block();
System.out.println(fixedFunctionResult.getResult());
@@ -92,7 +92,7 @@ public class Example06_TemplateLanguage {
System.out.println(renderedPrompt);
var kindOfDay = KernelFunctionFactory
.createFromPrompt(
.<String>createFromPrompt(
functionDefinition,
new Builder()
.withMaxTokens(100)
@@ -104,7 +104,7 @@ public class Example06_TemplateLanguage {
// Show the result
System.out.println("--- Prompt Function result");
var result = kernel.invokeAsync(kindOfDay, null, String.class).block();
var result = kernel.invokeAsync(kindOfDay, null).block();
System.out.println(result.getResult());
}
}
@@ -8,8 +8,10 @@ import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.connectors.web.bing.BingConnector;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.plugins.web.WebSearchEnginePlugin;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
@@ -82,12 +84,12 @@ public class Example07_BingAndGooglePlugins {
// Run
var question = "What's the largest building in the world?";
var kernelArguments = KernelArguments.builder()
var kernelArguments = KernelFunctionArguments.builder()
.withVariable("query", question)
.build();
var function = kernel.getPlugins().getFunction(searchPluginName, "search");
var result = kernel.invokeAsync(function, kernelArguments, String.class).block();
var result = kernel.invokeAsync(function, kernelArguments).block();
System.out.println(question);
System.out.printf("----%s----%n", searchPluginName);
@@ -155,17 +157,17 @@ public class Example07_BingAndGooglePlugins {
.withTopP(1)
.build();
var oracle = KernelFunctionFromPrompt.builder()
KernelFunction<String> oracle = KernelFunctionFromPrompt.<String>builder()
.withTemplate(semanticFunction)
.withDefaultExecutionSettings(promptExecutionSettings)
.build();
var kernelArguments = KernelArguments.builder()
var kernelArguments = KernelFunctionArguments.builder()
.withVariable("question", question)
.withVariable("externalInformation", "")
.build();
var answer = kernel.invokeAsync(oracle, kernelArguments, String.class).block();
FunctionResult<String> answer = kernel.invokeAsync(oracle, kernelArguments).block();
var result = answer.getResult();
@@ -181,13 +183,13 @@ public class Example07_BingAndGooglePlugins {
System.out.println("Information found:");
System.out.println(information);
kernelArguments = KernelArguments.builder()
kernelArguments = KernelFunctionArguments.builder()
.withVariable("question", question)
.withVariable("externalInformation", information)
.build();
// Run the prompt function again, now including information from Bing
answer = kernel.invokeAsync(oracle, kernelArguments, String.class).block();
answer = kernel.invokeAsync(oracle, kernelArguments).block();
}
else
{
@@ -39,11 +39,11 @@ public class Example08_RetryHandler {
String question = "How popular is the Polly library?";
KernelFunction fuction = KernelFunctionFromPrompt.create(question);
KernelFunction<String> fuction = KernelFunctionFromPrompt.create(question);
try {
// Will retry 3 times with exponential backoff
kernel.invokeAsync(fuction, null, String.class).block();
kernel.invokeAsync(fuction, null).block();
} catch (Exception e) {
System.out.println("Hit max retries");
}
@@ -8,11 +8,11 @@ import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter.NoopConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.plugin.annotations.DefineKernelFunction;
@@ -120,17 +120,18 @@ public class Example09_FunctionTypes {
.build();
// Different ways to invoke a function (not limited to these examples)
FunctionResult<?> result = kernel.invokeAsync(plugin.get("NoInputWithVoidResult"), null,
String.class).block();
System.out.println(result.getResult());
result = kernel.invokeAsync(plugin.get("NoInputTaskWithVoidResult"), null, String.class)
FunctionResult<?> result = kernel.invokeAsync(plugin.get("NoInputWithVoidResult"), null).block();
assert result == null;
System.out.println(result != null ? result.getResult() : "null");
result = kernel.invokeAsync(plugin.get("NoInputTaskWithVoidResult"), null)
.block();
System.out.println(result.getResult());
assert result == null;
System.out.println(result != null ? result.getResult() : "null");
result = kernel
.invokeAsync(
plugin.get("InputDateTimeWithStringResult"),
KernelArguments
plugin.<String>get("InputDateTimeWithStringResult"),
KernelFunctionArguments
.builder()
.withVariable("currentDate",
ContextVariable.of(
@@ -138,29 +139,27 @@ public class Example09_FunctionTypes {
new DateTimeContextVariableTypeConverter()
)
)
.build(),
String.class
.build()
).block();
System.out.println(result.getResult());
result = kernel.invokeAsync(plugin.get("NoInputTaskWithStringResult"), null, String.class)
result = kernel.invokeAsync(plugin.<String>get("NoInputTaskWithStringResult"), null)
.block();
System.out.println(result.getResult());
result = kernel.invokeAsync(plugin.get("MultipleInputsWithVoidResult"),
KernelArguments
kernel.invokeAsync(plugin.<String>get("MultipleInputsWithVoidResult"),
KernelFunctionArguments
.builder()
.withVariable("x", "x string")
.withVariable("y", 100)
.withVariable("z", 1.5)
.build(),
String.class)
.build())
.block();
System.out.println(result.getResult());
result = kernel
.invokeAsync(plugin.get("ComplexInputWithStringResult"),
KernelArguments
.invokeAsync(plugin.<String>get("ComplexInputWithStringResult"),
KernelFunctionArguments
.builder()
.withVariable(
"complexObject",
@@ -174,44 +173,41 @@ public class Example09_FunctionTypes {
new NoopConverter<>(Object.class)
)
)
.build(),
String.class)
.build())
.block();
System.out.println(result.getResult());
result = kernel
.invokeAsync(plugin.get("InputStringTaskWithStringResult"),
KernelArguments
.invokeAsync(plugin.<String>get("InputStringTaskWithStringResult"),
KernelFunctionArguments
.builder()
.withVariable("echoInput", "return this")
.build(),
String.class)
.build())
.block();
System.out.println(result.getResult());
result = kernel
.invokeAsync(plugin.get("InputStringTaskWithVoidResult"),
KernelArguments
.invokeAsync(plugin.<String>get("InputStringTaskWithVoidResult"),
KernelFunctionArguments
.builder()
.withVariable("x", "x input")
.build(),
Void.class)
.build()
)
.block();
assert result == null;
System.out.println(result != null ? result.getResult() : "null");
result = kernel
.invokeAsync(plugin.<String>get("noInputComplexReturnTypeAsync"),
null)
.block();
System.out.println(result.getResult());
result = kernel
.invokeAsync(plugin.get("noInputComplexReturnTypeAsync"),
null,
Temporal.class)
var temporalResult = kernel
.invokeAsync(plugin.<Temporal>get("noInputComplexReturnType"),
null)
.block();
System.out.println(result.getResult());
result = kernel
.invokeAsync(plugin.get("noInputComplexReturnType"),
null,
Temporal.class)
.block();
System.out.println(result.getResult());
System.out.println(temporalResult.getResult());
// Possibilities for return type combinations:
// | Method return type | Declared Function Return Type | Invocation Return type |
@@ -223,54 +219,48 @@ public class Example09_FunctionTypes {
// | T | U extends T | U |
// | T | U extends T | V converted from U |
result = kernel
.invokeAsync(plugin.get("conversionScenarioA"),
null,
OffsetDateTime.class)
var result1 = kernel
.invokeAsync(plugin.<OffsetDateTime>get("conversionScenarioA"),
null)
.block();
System.out.println(result.getResult());
System.out.println(result1.getResult());
result = kernel
.invokeAsync(plugin.get("conversionScenarioA"),
null,
Instant.class)
var result2 = kernel
.invokeAsync(plugin.<Instant>get("conversionScenarioA"),
null)
.block();
System.out.println(result.getResult());
System.out.println(result2.getResult());
result = kernel
.invokeAsync(plugin.get("conversionScenarioB"),
null,
OffsetDateTime.class)
var result3 = kernel
.invokeAsync(plugin.<OffsetDateTime>get("conversionScenarioB"),
null)
.block();
System.out.println(result.getResult());
System.out.println(result3.getResult());
result = kernel
.invokeAsync(plugin.get("conversionScenarioB"),
null,
Temporal.class)
var result4 = kernel
.invokeAsync(plugin.<Temporal>get("conversionScenarioB"),
null)
.block();
System.out.println(result.getResult());
System.out.println(result4.getResult());
result = kernel
.invokeAsync(plugin.get("conversionScenarioB"),
null,
Instant.class)
var result5 = kernel
.invokeAsync(plugin.<Instant>get("conversionScenarioB"),
null
)
.block();
System.out.println(result.getResult());
System.out.println(result5.getResult());
result = kernel
var result6 = kernel
.invokeAsync(plugin.get("noInputComplexReturnType"),
null,
String.class)
null)
.block();
System.out.println(result.getResult());
System.out.println(result6.getResult());
result = kernel
var result7 = kernel
.invokeAsync(plugin.get("withDefaultValue"),
null,
String.class)
null)
.block();
System.out.println(result.getResult());
System.out.println(result7.getResult());
/*
TODO: support FunctionResult
@@ -306,8 +296,7 @@ public class Example09_FunctionTypes {
.invokeAsync(
kernel.getPlugins()
.getFunction("Examples", "NoInputWithVoidResult"),
null,
Void.class)
null)
.block();
}
@@ -317,7 +306,7 @@ public class Example09_FunctionTypes {
/// <summary>
/// Example of using a void function with no input
/// </summary>
@DefineKernelFunction(name = "NoInputWithVoidResult")
@DefineKernelFunction(name = "NoInputWithVoidResult", returnType="void")
public void NoInputWithVoidResult() {
System.out.println("Running this.NoInputWithVoidResult) -> No input");
}
@@ -9,13 +9,16 @@ import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextG
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionMetadata;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.plugin.KernelParameterMetadata;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.plugin.annotations.DefineKernelFunction;
import com.microsoft.semantickernel.plugin.annotations.KernelFunctionParameter;
import com.microsoft.semantickernel.samples.plugins.text.TextPlugin;
import com.microsoft.semantickernel.plugins.text.TextPlugin;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
import com.microsoft.semantickernel.textcompletion.TextGenerationService;
import java.nio.file.Path;
import java.util.List;
import java.util.Locale;
public class Example10_DescribeAllPluginsAndFunctions {
@@ -154,7 +157,7 @@ public class Example10_DescribeAllPluginsAndFunctions {
});
}
private static void printFunction(KernelFunctionMetadata func) {
private static void printFunction(KernelFunctionMetadata<?> func) {
System.out.println(" " + func.getName() + ": " + func.getDescription());
if (!func.getParameters().isEmpty()) {
@@ -1,7 +1,7 @@
package com.microsoft.semantickernel.samples.syntaxexamples;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.plugins.web.SearchUrlPlugin;
@@ -17,11 +17,11 @@ public class Example11_WebSearchQueries {
// Run
var ask = "What's the largest building in Europe?";
var kernelArguments = KernelArguments.builder()
var kernelArguments = KernelFunctionArguments.builder()
.withVariable("query", ask)
.build();
var result = kernel.invokeAsync(bingSearchFunction, kernelArguments, String.class).block();
var result = kernel.invokeAsync(bingSearchFunction, kernelArguments).block();
System.out.println(ask);
System.out.println(result.getResult());
@@ -8,12 +8,15 @@ import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService;
import com.microsoft.semantickernel.exceptions.ConfigurationException;
import com.microsoft.semantickernel.orchestration.contextvariables.DefaultKernelArguments.Builder;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments.Builder;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.samples.plugins.ConversationSummaryPlugin;
import com.microsoft.semantickernel.textcompletion.TextGenerationService;
import com.sun.jna.StringArray;
import reactor.core.publisher.Mono;
/**
@@ -34,7 +37,7 @@ public class Example13_ConversationSummaryPlugin {
.getOrDefault("MODEL_ID", "text-davinci-003");
private static final String ChatTranscript =
private static final String chatTranscript =
"""
John: Hello, how are you?
Jane: I'm fine, thanks. How are you?
@@ -161,12 +164,10 @@ public class Example13_ConversationSummaryPlugin {
Mono<FunctionResult<String>> summary = kernel
.invokeAsync(
conversationSummaryPlugin
.getFunctions()
.get("GetConversationActionItems"),
.<String>get("GetConversationActionItems"),
new Builder()
.withInput(ChatTranscript)
.build(),
String.class
.withInput(chatTranscript)
.build()
);
System.out.println("Generated Action Items:");
@@ -182,12 +183,10 @@ public class Example13_ConversationSummaryPlugin {
Mono<FunctionResult<String>> summary = kernel
.invokeAsync(
conversationSummaryPlugin
.getFunctions()
.get("GetConversationTopics"),
.<String>get("GetConversationTopics"),
new Builder()
.withInput(ChatTranscript)
.build(),
String.class
.withInput(chatTranscript)
.build()
);
System.out.println("Generated Topics:");
@@ -203,15 +202,14 @@ public class Example13_ConversationSummaryPlugin {
KernelPlugin conversationSummaryPlugin = KernelPluginFactory.createFromObject(
new ConversationSummaryPlugin(), null);
FunctionResult<String> summary = kernel
FunctionResult<?> summary = kernel
.invokeAsync(
conversationSummaryPlugin
.getFunctions()
.get("SummarizeConversation"),
new Builder()
.withInput(ChatTranscript)
.build(),
String.class
.withInput(chatTranscript)
.build()
).block();
System.out.println("Generated Summary (This may take some time):");
@@ -40,7 +40,7 @@ public class Example26_AADAuth {
chatHistory.addUserMessage("Tell me a joke about hourglasses");
// Bot reply
var reply = chatService.getChatMessageContentsAsync(chatHistory, null, kernel).block();
var reply = chatService.getChatMessageContentsAsync(chatHistory, kernel, null).block();
System.out.println(reply);
}
}
@@ -6,8 +6,8 @@ import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelFunctionFactory;
public class Example27_PromptFunctionsUsingChatGPT {
@@ -47,12 +47,12 @@ public class Example27_PromptFunctionsUsingChatGPT {
.withAIService(ChatCompletionService.class, openAIChatCompletion)
.build();
var func = KernelFunctionFactory.createFromPrompt(
var func = KernelFunctionFactory.<String>createFromPrompt(
"List the two planets closest to '{{$input}}', excluding moons, using bullet points.");
var result = func.invokeAsync(
kernel,
KernelArguments.builder()
KernelFunctionArguments.builder()
.withVariable("input", "Jupiter")
.build(),
ContextVariableTypes.getDefaultVariableTypeForClass(String.class)
@@ -8,7 +8,7 @@ import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.ServiceNotFoundException;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.samples.plugins.TimePlugin;
@@ -78,7 +78,7 @@ public class Example30_ChatWithPrompts {
// Adding required arguments referenced by the prompt templates.
var arguments = KernelArguments
var arguments = KernelFunctionArguments
.builder()
.withVariable("selectedText", selectedText)
.withVariable("startTime", DateTimeFormatter.ofPattern("hh:mm:ss a zz").format(
@@ -117,7 +117,7 @@ public class Example30_ChatWithPrompts {
// Finally, get the response from AI
var answer = chatCompletion
.getChatMessageContentsAsync(chatHistory, null, kernel)
.getChatMessageContentsAsync(chatHistory, kernel, null)
.block();
System.out.println(
"------------------------------------\n" + answer.stream().findFirst().get()
@@ -9,7 +9,7 @@ import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatC
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
public class Example43_GetModelResult {
@@ -53,16 +53,15 @@ public class Example43_GetModelResult {
// Create function
String FunctionDefinition = "Hi, give me 5 book suggestions about: {{$input}}";
KernelFunction myFunction = KernelFunctionFromPrompt.create(
KernelFunction<String> myFunction = KernelFunctionFromPrompt.create(
FunctionDefinition);
// Invoke function through kernel
FunctionResult<String> result = kernel.invokeAsync(
myFunction,
KernelArguments.builder()
KernelFunctionArguments.builder()
.withVariable("input", "travel")
.build(),
String.class)
.build())
.block();
// Display results
@@ -7,6 +7,7 @@ import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.orchestration.InvocationContext;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
public class Example44_MultiChatCompletion {
@@ -65,7 +66,10 @@ public class Example44_MultiChatCompletion {
private static void GPTReply(ChatCompletionService chatGPT, ChatHistory chatHistory,
PromptExecutionSettings settings) {
var reply = chatGPT.getChatMessageContentsAsync(chatHistory, settings, null)
var invocationContext = InvocationContext.builder().withPromptExecutionSettings(settings).build();
var reply = chatGPT.getChatMessageContentsAsync(chatHistory, null, invocationContext)
.block();
reply.forEach(chatMessageContent -> {
@@ -7,6 +7,7 @@ import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.orchestration.InvocationContext;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import java.util.Arrays;
import java.util.HashMap;
@@ -75,6 +76,8 @@ public class Example49_LogitBias {
.withTokenSelectionBiases(biases)
.build();
var invocationContext = InvocationContext.builder().withPromptExecutionSettings(settings).build();
System.out.println("Chat content:");
System.out.println("------------------------");
@@ -85,7 +88,7 @@ public class Example49_LogitBias {
messageOutputAsync(chatHistory);
var replyMessage = openAIChatCompletion.getChatMessageContentsAsync(chatHistory,
settings, kernel).block();
kernel, invocationContext).block();
replyMessage.forEach(message -> chatHistory.addAssistantMessage(message.getContent()));
messageOutputAsync(chatHistory);
@@ -94,7 +97,7 @@ public class Example49_LogitBias {
messageOutputAsync(chatHistory);
replyMessage = openAIChatCompletion.getChatMessageContentsAsync(chatHistory,
settings, kernel).block();
kernel, invocationContext).block();
replyMessage.forEach(message -> chatHistory.addAssistantMessage(message.getContent()));
messageOutputAsync(chatHistory);
@@ -7,10 +7,10 @@ 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.KernelFunctionArguments;
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.plugins.text.TextPlugin;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
import com.microsoft.semantickernel.semanticfunctions.KernelPromptTemplateFactory;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
@@ -52,7 +52,7 @@ public class Example56_TemplateMethodFunctionsWithMultipleArguments {
System.out.println("======== TemplateMethodFunctionsWithMultipleArguments ========");
var arguments = KernelArguments.builder()
var arguments = KernelFunctionArguments.builder()
.withVariable("word2", " Potter")
.build();
@@ -84,7 +84,7 @@ public class Example56_TemplateMethodFunctionsWithMultipleArguments {
// Show the result
System.out.println("--- Prompt Function result");
var result = kernel.invokeAsync(haiku, arguments, String.class).block();
var result = kernel.invokeAsync(haiku, arguments).block();
System.out.println(result.getResult());
}
@@ -1,5 +1,9 @@
package com.microsoft.semantickernel.samples.syntaxexamples;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.ai.openai.models.ChatCompletionsOptions;
@@ -12,22 +16,21 @@ import com.microsoft.semantickernel.Kernel.Builder;
import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatCompletion;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.hooks.FunctionInvokedEvent;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokedHook;
import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokingHook;
import com.microsoft.semantickernel.hooks.KernelHook.PreChatCompletionHook;
import com.microsoft.semantickernel.hooks.KernelHook.PromptRenderedHook;
import com.microsoft.semantickernel.hooks.KernelHook.PromptRenderingHook;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.hooks.PreChatCompletionEvent;
import com.microsoft.semantickernel.hooks.PromptRenderedEvent;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.InvocationContext;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import com.microsoft.semantickernel.semanticfunctions.OutputVariable;
public class Example57_KernelHooks {
@@ -93,6 +96,7 @@ public class Example57_KernelHooks {
.withTemperature(0.4)
.withTopP(1)
.build())
.withOutputVariable(new OutputVariable("result", "java.lang.String"))
.build();
FunctionInvokingHook preHook = event -> {
@@ -117,23 +121,22 @@ public class Example57_KernelHooks {
return event;
};
kernel.getHookService().addHook(preHook);
kernel.getGlobalKernelHooks().addHook(preHook);
// Demonstrate pattern for removing a handler.
kernel.getHookService().addHook("pre-invoke-removed", removedPreExecutionHandler);
kernel.getHookService().removeHook("pre-invoke-removed");
kernel.getGlobalKernelHooks().addHook("pre-invoke-removed", removedPreExecutionHandler);
kernel.getGlobalKernelHooks().removeHook("pre-invoke-removed");
kernel.getHookService().addHook(postExecutionHandler);
kernel.getGlobalKernelHooks().addHook(postExecutionHandler);
// Invoke prompt to trigger execution hooks.
String input = "I missed the F1 final race";
var result = kernel.invokeAsync(
excuseFunction,
KernelArguments
KernelFunctionArguments
.builder()
.withVariable("input", input)
.build(),
String.class)
.build())
.block();
System.out.println("Function Result: " + result.getResult());
}
@@ -180,17 +183,16 @@ public class Example57_KernelHooks {
prompt
);
};
kernel.getHookService().addHook(myRenderingHandler);
kernel.getHookService().addHook(myRenderedHandler);
kernel.getGlobalKernelHooks().addHook(myRenderingHandler);
kernel.getGlobalKernelHooks().addHook(myRenderedHandler);
// Invoke prompt to trigger execution hooks.
String input = "I missed the F1 final race";
var result = kernel.invokeAsync(excuseFunction,
KernelArguments
KernelFunctionArguments
.builder()
.withVariable("input", input)
.build(),
String.class)
.build())
.block();
System.out.println("Function Result: " + result.getResult());
}
@@ -230,13 +232,12 @@ public class Example57_KernelHooks {
)
);
};
kernel.getHookService().addHook(hook);
kernel.getGlobalKernelHooks().addHook(hook);
// Invoke prompt to trigger execution hooks.
var result = kernel.invokeAsync(
writerFunction,
KernelArguments.builder().build(),
String.class)
KernelFunctionArguments.builder().build())
.block();
System.out.println("Function Result: " + result.getResult());
}
@@ -271,14 +272,13 @@ public class Example57_KernelHooks {
throw new RuntimeException("Cancelled");
};
kernel.getHookService().addHook(hook);
kernel.getGlobalKernelHooks().addHook(hook);
try {
// Invoke prompt to trigger execution hooks.
var result = kernel.invokeAsync(
writerFunction,
KernelArguments.builder().build(),
String.class)
KernelFunctionArguments.builder().build())
.block();
System.out.println("Function Result: " + result.getResult());
} catch (Exception e) {
@@ -300,13 +300,13 @@ public class Example57_KernelHooks {
var secondFunction = KernelFunctionFromPrompt.create("Write a phrase with Cancellation.");
AtomicInteger invokingCounter = new AtomicInteger(0);
kernel.getHookService().addHook((FunctionInvokingHook) event -> {
kernel.getGlobalKernelHooks().addHook((FunctionInvokingHook) event -> {
invokingCounter.incrementAndGet();
return event;
});
AtomicInteger invokedCounter = new AtomicInteger(0);
kernel.getHookService().addHook((FunctionInvokedHook) event -> {
kernel.getGlobalKernelHooks().addHook((FunctionInvokedHook) event -> {
invokedCounter.incrementAndGet();
throw new RuntimeException("Cancelled");
});
@@ -315,8 +315,7 @@ public class Example57_KernelHooks {
try {
var result = kernel.invokeAsync(
secondFunction,
KernelArguments.builder().build(),
String.class)
KernelFunctionArguments.builder().build())
.block();
System.out.println("Function Result: " + result.getResult());
} catch (Exception e) {
@@ -341,7 +340,7 @@ public class Example57_KernelHooks {
.build())
.build();
kernel.getHookService().addPreChatCompletionHook(event -> {
kernel.getGlobalKernelHooks().addPreChatCompletionHook(event -> {
ChatCompletionsOptions options = event.getOptions();
List<ChatRequestMessage> messages = options.getMessages();
@@ -358,8 +357,7 @@ public class Example57_KernelHooks {
// Invoke prompt to trigger execution hooks.
var result = kernel.invokeAsync(
writerFunction,
KernelArguments.builder().build(),
String.class)
KernelFunctionArguments.builder().build())
.block();
System.out.println("Function Result: " + result.getResult());
} catch (Exception e) {
@@ -401,13 +399,17 @@ public class Example57_KernelHooks {
);
});
InvocationContext invocationContext = InvocationContext.builder()
.withKernelHooks(kernelHooks)
.build();
try {
// Invoke prompt to trigger execution hooks.
var result = kernel.invokeAsync(
writerFunction,
KernelArguments.builder().build(),
kernelHooks,
String.class)
KernelFunctionArguments.builder().build(),
null,
invocationContext)
.block();
System.out.println("Function Result: " + result.getResult());
} catch (Exception e) {
@@ -10,6 +10,7 @@ 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.OutputVariable;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
public class Example58_ConfigureExecutionSettings {
@@ -60,9 +61,10 @@ public class Example58_ConfigureExecutionSettings {
.withMaxTokens(60)
.withTemperature(0.7)
.build()
).build(),
null,
String.class
)
.withOutputVariable(new OutputVariable("result", "java.lang.String"))
.build(),
null
).block();
System.out.println(result.getResult());
@@ -91,7 +93,7 @@ public class Example58_ConfigureExecutionSettings {
var func = KernelFunctionFactory.createFromPrompt(promptConfig, null);
result = kernel.invokeAsync(func, null, String.class).block();
result = kernel.invokeAsync(func, null).block();
System.out.println(result.getResult());
}
}
@@ -9,7 +9,7 @@ import com.microsoft.semantickernel.aiservices.openai.chatcompletion.OpenAIChatC
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.plugin.annotations.DefineKernelFunction;
import reactor.core.publisher.Mono;
@@ -71,7 +71,7 @@ public class Example60_AdvancedMethodFunctions {
.invokeAsync(
FunctionsChainingPlugin.PluginName,
"Function1",
KernelArguments
KernelFunctionArguments
.builder()
.build(),
ContextVariableTypes.getDefaultVariableTypeForClass(MyCustomType.class)
@@ -123,7 +123,7 @@ public class Example60_AdvancedMethodFunctions {
.invokeAsync(
PluginName,
"Function2",
KernelArguments.builder().build(),
KernelFunctionArguments.builder().build(),
ContextVariableTypes.getDefaultVariableTypeForClass(
Example60_AdvancedMethodFunctions.MyCustomType.class))
.flatMap(value -> {
@@ -7,9 +7,10 @@ import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
import com.microsoft.semantickernel.semanticfunctions.OutputVariable;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.textcompletion.TextGenerationService;
import java.util.Arrays;
@@ -72,9 +73,9 @@ public class Example61_MultipleLLMs {
var prompt = "Hello AI, what can you do for me?";
KernelArguments arguments = KernelArguments.builder().build();
KernelFunctionArguments arguments = KernelFunctionArguments.builder().build();
KernelFunction func = KernelFunctionFromPrompt
KernelFunction<?> func = KernelFunctionFromPrompt
.builder()
.withTemplate(prompt)
.withDefaultExecutionSettings(
@@ -82,9 +83,10 @@ public class Example61_MultipleLLMs {
.withServiceId(serviceId)
.build()
)
.withOutputVariable("result", "java.lang.String")
.build();
var result = kernel.invokeAsync(func, arguments, String.class).block();
var result = kernel.invokeAsync(func, arguments).block();
System.out.println(result.getResult());
}
@@ -103,9 +105,9 @@ public class Example61_MultipleLLMs {
.withModelId(modelId)
.build()
)
.withOutputVariable("result", "java.lang.String")
.build(),
KernelArguments.builder().build(),
String.class
KernelFunctionArguments.builder().build()
).block();
System.out.println(result.getResult());
@@ -137,8 +139,7 @@ public class Example61_MultipleLLMs {
var result = kernel.invokeAsync(
function,
KernelArguments.builder().build(),
String.class)
KernelFunctionArguments.builder().build())
.block();
System.out.println(result.getResult());
@@ -8,8 +8,8 @@ import com.microsoft.semantickernel.AIService;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
import com.microsoft.semantickernel.services.AIServiceSelection;
import com.microsoft.semantickernel.services.BaseAIServiceSelector;
@@ -64,9 +64,9 @@ public class Example62_CustomAIServiceSelector {
var prompt = "Hello AI, what can you do for me?";
KernelArguments arguments = KernelArguments.builder().build();
KernelFunctionArguments arguments = KernelFunctionArguments.builder().build();
KernelFunction func = KernelFunctionFromPrompt
KernelFunction<?> func = KernelFunctionFromPrompt
.builder()
.withTemplate(prompt)
.withDefaultExecutionSettings(
@@ -74,9 +74,10 @@ public class Example62_CustomAIServiceSelector {
.withTopP(1.0)
.build()
)
.withOutputVariable("result", "java.lang.String")
.build();
var result = kernel.invokeAsync(func, arguments, String.class).block();
var result = kernel.invokeAsync(func, arguments).block();
System.out.println(result.getResult());
}
@@ -89,25 +90,28 @@ public class Example62_CustomAIServiceSelector {
@Nullable
@Override
@SuppressWarnings("unchecked")
public <T extends AIService> AIServiceSelection<T> trySelectAIService(
Class<T> serviceType,
@Nullable
KernelFunction function,
KernelFunction<?> function,
@Nullable
KernelArguments arguments,
Map<Class<? extends AIService>, AIService> services) {
KernelFunctionArguments arguments,
Map<Class<? extends AIService>, AIService> services) {
// Just get the first one
PromptExecutionSettings executionSettings = function.getExecutionSettings()
.values().stream().findFirst().get();
AIService service = services.values().stream().findFirst().get();
// unchecked cast
T service = (T)services.values().stream().findFirst().get();
return new AIServiceSelection(
return new AIServiceSelection<>(
service,
executionSettings
);
}
}
}
@@ -50,7 +50,7 @@ public class Example63_ChatCompletionPrompts {
""".stripIndent();
var chatSemanticFunction = KernelFunctionFromPrompt.create(chatPrompt);
var chatPromptResult = kernel.invokeAsync(chatSemanticFunction, null, String.class).block();
var chatPromptResult = kernel.invokeAsync(chatSemanticFunction, null).block();
System.out.println("Chat Prompt:");
System.out.println(chatPrompt);
@@ -60,7 +60,7 @@ public class Example63_ChatCompletionPrompts {
CountDownLatch cdl = new CountDownLatch(1);
System.out.println("Chat Prompt Result:");
kernel
.invokeAsync(chatSemanticFunction, null, String.class)
.invokeAsync(chatSemanticFunction, null)
.doFinally(x -> cdl.countDown())
.subscribe(result -> System.out.println(result.getResult()));
@@ -7,7 +7,7 @@ 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.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.semanticfunctions.AggregatorPromptTemplateFactory;
import com.microsoft.semantickernel.semanticfunctions.HandlebarsPromptTemplateFactory;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromPrompt;
@@ -71,17 +71,17 @@ public class Example64_MultiplePromptTemplates {
public static void runPrompt(Kernel kernel, String templateFormat, String prompt,
PromptTemplateFactory templateFactory) {
var function = new KernelFunctionFromPrompt.Builder()
var function = new KernelFunctionFromPrompt.Builder<>()
.withTemplate(prompt)
.withTemplateFormat(templateFormat)
.withPromptTemplateFactory(templateFactory)
.build();
var arguments = KernelArguments.builder()
var arguments = KernelFunctionArguments.builder()
.withVariable("name", "Bob")
.build();
var result = kernel.invokeAsync(function, arguments, String.class).block();
var result = kernel.invokeAsync(function, arguments).block();
System.out.println(result.getResult());
}
}
@@ -32,7 +32,7 @@ public class Example69_MutableKernelPlugin {
kernel.getPlugins().add(plugin);
var result = kernel.invokeAsync(kernel.getPlugins().getFunction("Plugin", "dateFunction"),
null, String.class).block();
null).block();
System.out.println("Result: " + result.getResult());
}
@@ -13,6 +13,7 @@
"input_variables": [
{
"name": "input",
"type": "java.lang.String",
"description": "Text to summarize",
"default": "",
"is_required": true
@@ -5,9 +5,9 @@ import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionYaml;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplate;
import java.io.BufferedReader;
import java.io.IOException;
@@ -46,7 +46,7 @@ public class Main {
.build();
// Initialize the required functions and services for the kernel
KernelFunction chatFunction = KernelFunctionYaml.fromYaml(
KernelFunction<String> chatFunction = KernelFunctionYaml.fromYaml(
Path.of("Plugins/ChatPlugin/SimpleChat.prompt.yaml"));
ChatHistory chatHistory = new ChatHistory();
@@ -60,11 +60,10 @@ public class Main {
FunctionResult<String> message = kernel
.invokeAsync(
chatFunction,
KernelArguments
KernelFunctionArguments
.builder()
.withVariable("messages", chatHistory)
.build(),
String.class
.build()
)
.block();
@@ -5,8 +5,9 @@ import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.chatcompletion.ChatMessageContent;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionYaml;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
@@ -67,7 +68,7 @@ public class SimpleChatTest {
.build();
// Initialize the required functions and services for the kernel
KernelFunction chatFunction = KernelFunctionYaml.fromYaml(
KernelFunction<String> chatFunction = KernelFunctionYaml.fromYaml(
Path.of("Plugins/ChatPlugin/SimpleChat.prompt.yaml"));
ChatHistory chatHistory = new ChatHistory();
@@ -78,11 +79,10 @@ public class SimpleChatTest {
FunctionResult<String> result = kernel
.invokeAsync(
chatFunction,
KernelArguments
KernelFunctionArguments
.builder()
.withVariable("messages", chatHistory)
.build(),
String.class
.build()
)
.block();
@@ -5,9 +5,9 @@ import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionYaml;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplate;
import java.io.BufferedReader;
import java.io.IOException;
@@ -31,7 +31,7 @@ public class Main {
.buildAsyncClient();
// Initialize the required functions and services for the kernel
KernelFunction chatFunction = KernelFunctionYaml.fromYaml(
KernelFunction<String> chatFunction = KernelFunctionYaml.fromYaml(
Path.of("Plugins/ChatPlugin/PersonaChat.prompt.yaml"));
ChatCompletionService gpt35Turbo = ChatCompletionService.builder()
@@ -57,13 +57,12 @@ public class Main {
FunctionResult<String> message = kernel
.invokeAsync(
chatFunction,
KernelArguments
KernelFunctionArguments
.builder()
.withVariable("messages", chatHistory)
.withVariable("persona",
"You are a snarky (yet helpful) teenage assistant. Make sure to use hip slang in every response.")
.build(),
String.class
.build()
)
.block();
@@ -4,9 +4,9 @@ import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.chatcompletion.ChatMessageContent;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionYaml;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplate;
import java.io.IOException;
import java.nio.file.Path;
@@ -62,7 +62,7 @@ public class PersonaChatTest {
.build();
// Initialize the required functions and services for the kernel
KernelFunction chatFunction = KernelFunctionYaml.fromYaml(
KernelFunction<String> chatFunction = KernelFunctionYaml.fromYaml(
Path.of("Plugins/ChatPlugin/PersonaChat.prompt.yaml"));
ChatHistory chatHistory = new ChatHistory();
@@ -73,13 +73,12 @@ public class PersonaChatTest {
FunctionResult<String> result = kernel
.invokeAsync(
chatFunction,
KernelArguments
KernelFunctionArguments
.builder()
.withVariable("messages", chatHistory)
.withVariable("persona",
"You are a snarky (yet helpful) teenage assistant. Make sure to use hip slang in every response.")
.build(),
String.class
.build()
)
.block();
@@ -1,18 +1,19 @@
import java.io.IOException;
import java.nio.file.Path;
import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionYaml;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionYaml;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplate;
import java.io.IOException;
import java.nio.file.Path;
import plugins.searchplugin.Search;
public class Main {
@@ -33,7 +34,7 @@ public class Main {
.buildAsyncClient();
// Initialize the required functions and services for the kernel
KernelFunction chatFunction = KernelFunctionYaml.fromYaml(
KernelFunction<String> chatFunction = KernelFunctionYaml.fromYaml(
Path.of("Plugins/ChatPlugin/GroundedChat.prompt.yaml"));
ChatCompletionService gpt35Turbo = ChatCompletionService.builder()
@@ -63,12 +64,11 @@ public class Main {
FunctionResult<String> message = kernel
.invokeAsync(
chatFunction,
KernelArguments.builder()
KernelFunctionArguments.builder()
.withVariable("messages", chatHistory)
.withVariable("persona",
"You are a snarky (yet helpful) teenage assistant. Make sure to use hip slang in every response.")
.build(),
String.class
.build()
)
.block();
@@ -4,9 +4,9 @@ import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.chatcompletion.ChatMessageContent;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionYaml;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplate;
@@ -59,7 +59,7 @@ public class SimpleRagTest {
);
// Initialize the required functions and services for the kernel
KernelFunction chatFunction = KernelFunctionYaml.fromYaml(
KernelFunction<String> chatFunction = KernelFunctionYaml.fromYaml(
Path.of("Plugins/ChatPlugin/GroundedChat.prompt.yaml"));
ChatCompletionService gpt35Turbo = mockService(messages);
@@ -86,12 +86,11 @@ public class SimpleRagTest {
FunctionResult<String> result = kernel
.invokeAsync(
chatFunction,
KernelArguments.builder()
KernelFunctionArguments.builder()
.withVariable("messages", chatHistory)
.withVariable("persona",
"You are a snarky (yet helpful) teenage assistant. Make sure to use hip slang in every response.")
.build(),
String.class
.build()
)
.block();
@@ -1,34 +1,36 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.exceptions.SKException;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.FunctionResultMetadata;
import com.microsoft.semantickernel.orchestration.InvocationContext;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter.NoopConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.contextvariables.NullContextVariable;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginCollection;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
import com.microsoft.semantickernel.services.AIServiceSelection;
import com.microsoft.semantickernel.services.AIServiceSelector;
import com.microsoft.semantickernel.services.OrderedAIServiceSelector;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
/**
@@ -40,12 +42,12 @@ public class Kernel implements Buildable {
private final AIServiceSelector serviceSelector;
private final KernelPluginCollection plugins;
private final KernelHooks kernelHooks;
private final KernelHooks globalKernelHooks;
public Kernel(
AIServiceSelector serviceSelector,
@Nullable KernelPluginCollection plugins,
@Nullable KernelHooks kernelHooks) {
@Nullable KernelHooks globalKernelHooks) {
this.serviceSelector = serviceSelector;
if (plugins != null) {
@@ -54,106 +56,82 @@ public class Kernel implements Buildable {
this.plugins = new KernelPluginCollection();
}
this.kernelHooks = new KernelHooks(kernelHooks);
this.globalKernelHooks = new KernelHooks(globalKernelHooks);
}
public <T> Mono<FunctionResult<T>> invokeAsync(
KernelFunction function,
@Nullable KernelArguments arguments,
@Nullable KernelHooks kernelHooks,
ContextVariableType<T> resultType) {
kernelHooks = mergeInGlobalHooks(kernelHooks);
return function.invokeAsync(this, arguments, kernelHooks, resultType);
KernelFunction<T> function,
@Nullable KernelFunctionArguments arguments) {
return invokeAsync(function, arguments, null);
}
public <T> Mono<FunctionResult<T>> invokeAsync(
KernelFunction function,
@Nullable KernelArguments arguments,
ContextVariableType<T> resultType) {
return invokeAsync(function, arguments, null, resultType);
}
public <T> Mono<FunctionResult<T>> invokeAsync(
String pluginName,
String functionName,
@Nullable KernelArguments arguments,
@Nullable KernelHooks kernelHooks,
ContextVariableType<T> resultType) {
kernelHooks = mergeInGlobalHooks(kernelHooks);
return plugins.getFunction(pluginName, functionName)
.invokeAsync(this, arguments, kernelHooks, resultType);
KernelFunction<T> function,
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> variableType) {
return invokeAsync(function, arguments, variableType, null);
}
public <T> Mono<FunctionResult<T>> invokeAsync(
String pluginName,
String functionName,
@Nullable KernelArguments arguments,
ContextVariableType<T> resultType) {
return invokeAsync(pluginName, functionName, arguments, null, resultType);
}
KernelFunction<T> function,
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> variableType,
@Nullable InvocationContext invocationContext) {
Objects.requireNonNull(function, "function");
public <T> Mono<FunctionResult<T>> invokeAsync(
KernelFunction function,
@Nullable KernelArguments arguments,
@Nullable KernelHooks kernelHooks,
Class<T> resultType) {
// Ever other invokeAsync call should end up here...
kernelHooks = mergeInGlobalHooks(kernelHooks);
ContextVariableType<?> contextVariable = getContextVariableType(function, resultType);
return function
.invokeAsync(this, arguments, kernelHooks, contextVariable)
.map(it -> {
return new FunctionResult<>(
ContextVariable.convert(it.getResult(), resultType),
it.getMetadata()
);
})
.defaultIfEmpty(
new FunctionResult<>(
new NullContextVariable<>(resultType),
new FunctionResultMetadata()));
}
@Nullable
private static <T> ContextVariableType<?> getContextVariableType(
KernelFunction function,
Class<T> resultType) {
Class functionReturnType = function.getMetadata().getReturnParameter().getParameterType();
try {
return ContextVariableTypes.getDefaultVariableTypeForClass(
functionReturnType);
} catch (Exception e) {
if (functionReturnType.isAssignableFrom(resultType)) {
return new ContextVariableType<>(
new NoopConverter<>(functionReturnType),
functionReturnType);
} else {
return null;
// If there are hooks added to the global kernel hooks, create a new invocation context
// with the global hooks and the invocation context hooks merged together.
KernelHooks hooks = new KernelHooks(getGlobalKernelHooks());
if (!hooks.isEmpty()) {
if (invocationContext != null) {
hooks.append(invocationContext.getKernelHooks());
}
InvocationContext.Builder builder = InvocationContext.builder()
.withKernelHooks(hooks);
if (invocationContext != null) {
builder = builder
.withPromptExecutionSettings(invocationContext.getPromptExecutionSettings())
.withToolCallBehavior(invocationContext.getToolCallBehavior());
}
invocationContext = builder.build();
}
return function.invokeAsync(this, arguments, variableType, invocationContext);
}
public <T> Mono<FunctionResult<T>> invokeAsync(
KernelFunction function,
@Nullable KernelArguments arguments,
Class<T> resultType) {
return invokeAsync(function, arguments, null, resultType);
String pluginName,
String functionName,
@Nullable KernelFunctionArguments arguments) {
return invokeAsync(pluginName, functionName, arguments, null);
}
private KernelHooks mergeInGlobalHooks(@Nullable KernelHooks kernelHooks) {
KernelHooks allKernelHooks = this.kernelHooks;
if (kernelHooks != null) {
allKernelHooks = allKernelHooks.append(kernelHooks);
public <T> Mono<FunctionResult<T>> invokeAsync(
String pluginName,
String functionName,
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> resultType) {
return invokeAsync(pluginName, functionName, arguments, resultType, null);
}
return allKernelHooks;
}
public List<KernelFunction> getFunctions() {
public <T> Mono<FunctionResult<T>> invokeAsync(
String pluginName,
String functionName,
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> variableType,
@Nullable InvocationContext invocationContext) {
KernelFunction function = plugins.getFunction(pluginName, functionName);
return invokeAsync(function, arguments, variableType, invocationContext);
}
public List<KernelFunction<?>> getFunctions() {
return plugins.getPlugins()
.stream()
.map(KernelPlugin::getFunctions)
@@ -172,8 +150,8 @@ public class Kernel implements Buildable {
@SuppressFBWarnings("EI_EXPOSE_REP")
public KernelHooks getHookService() {
return kernelHooks;
public KernelHooks getGlobalKernelHooks() {
return globalKernelHooks;
}
public <T extends AIService> T getService(Class<T> clazz) throws ServiceNotFoundException {
@@ -191,6 +169,72 @@ public class Kernel implements Buildable {
return selector.getService();
}
/*
// Add the global hooks to the invocation context hooks.
private KernelHooks mergeInGlobalHooks(@Nullable KernelHooks invocationContextHooks) {
KernelHooks mergedHooks = new KernelHooks();
KernelHooks kernelHooks = this.globalKernelHooks;
if (kernelHooks != null) {
mergedHooks = mergedHooks.append(kernelHooks);
}
if (invocationContextHooks != null) {
mergedHooks = mergedHooks.append(invocationContextHooks);
}
return mergedHooks;
}
// InvocationContext is immutable but it's members are not, so we need to create a new
// that can be modified (possibly) without affecting the original.
private InvocationContext updateInvocationContext(InvocationContext invocationContext) {
KernelFunctionArguments arguments = invocationContext.getKernelFunctionArguments();
if (arguments == null) {
arguments = new KernelFunctionArguments();
}
// Make a copy of the arguments in case they are modified by a hook later on.
KernelFunctionArguments updatedArguments = new KernelFunctionArguments(arguments);
updatedArguments.putAll(arguments);
// Add the global hooks to the invocation context hooks.
KernelHooks updatedHooks = mergeInGlobalHooks(invocationContext.getKernelHooks());
return new InvocationContext(
updatedArguments,
invocationContext.getFunctionReturnType(),
updatedHooks,
invocationContext.getPromptExecutionSettings());
}
@Nullable
@SuppressWarnings("unchecked")
static <T> ContextVariableType<T> getContextVariableType(
KernelFunction function,
Class<? extends T> resultType) {
Class<?> functionReturnType = function.getMetadata().getReturnParameter().getParameterType();
try {
// unchecked cast
return (ContextVariableType<T>) ContextVariableTypes.getDefaultVariableTypeForClass(
functionReturnType);
} catch (Exception e) {
if (functionReturnType.isAssignableFrom(resultType)) {
return new ContextVariableType<>(
// unchecked cast
new NoopConverter<>((Class<T>) functionReturnType),
// unchecked cast
(Class<T>) functionReturnType);
} else {
return null;
}
}
}
*/
public static Kernel.Builder builder() {
return new Kernel.Builder();
}
@@ -8,8 +8,7 @@ import com.microsoft.semantickernel.TextAIService;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.builders.ServiceLoadUtil;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.InvocationContext;
import java.util.List;
import javax.annotation.Nullable;
import reactor.core.publisher.Mono;
@@ -18,30 +17,14 @@ public interface ChatCompletionService extends Buildable, TextAIService {
Mono<List<ChatMessageContent>> getChatMessageContentsAsync(
ChatHistory chatHistory,
PromptExecutionSettings promptExecutionSettings,
Kernel kernel
@Nullable Kernel kernel,
@Nullable InvocationContext invocationContext
);
Mono<List<ChatMessageContent>> getChatMessageContentsAsync(
String prompt,
PromptExecutionSettings promptExecutionSettings,
Kernel kernel
);
Mono<List<ChatMessageContent>> getChatMessageContentsAsync(
ChatHistory chatHistory,
PromptExecutionSettings promptExecutionSettings,
Kernel kernel,
KernelHooks kernelHooks
);
Mono<List<ChatMessageContent>> getChatMessageContentsAsync(
String prompt,
@Nullable
PromptExecutionSettings promptExecutionSettings,
Kernel kernel,
@Nullable
KernelHooks kernelHooks
@Nullable Kernel kernel,
@Nullable InvocationContext invocationContext
);
static Builder builder() {
@@ -1,23 +1,26 @@
package com.microsoft.semantickernel.hooks;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
public class FunctionInvokedEvent<T> implements KernelHookEvent {
private final KernelFunction function;
@Nullable
private final KernelArguments arguments;
private final KernelFunctionArguments arguments;
private final FunctionResult<T> result;
public FunctionInvokedEvent(
KernelFunction function,
@Nullable KernelArguments arguments,
@Nullable KernelFunctionArguments arguments,
FunctionResult<T> result) {
this.function = function;
this.arguments = arguments;
this.arguments = arguments != null ? new KernelFunctionArguments(arguments) : new KernelFunctionArguments();
this.result = result;
}
@@ -25,11 +28,12 @@ public class FunctionInvokedEvent<T> implements KernelHookEvent {
return function;
}
@Nullable
public KernelArguments getArguments() {
@SuppressFBWarnings("EI_EXPOSE_REP")
public KernelFunctionArguments getArguments() {
return arguments;
}
@SuppressFBWarnings("EI_EXPOSE_REP")
public FunctionResult<T> getResult() {
return result;
}
@@ -1,26 +1,29 @@
package com.microsoft.semantickernel.hooks;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
public class FunctionInvokingEvent implements KernelHookEvent {
private final KernelFunction function;
@Nullable
private final KernelArguments arguments;
private final KernelFunctionArguments arguments;
public FunctionInvokingEvent(KernelFunction function, @Nullable KernelArguments arguments) {
public FunctionInvokingEvent(KernelFunction function,
@Nullable KernelFunctionArguments arguments) {
this.function = function;
this.arguments = arguments;
this.arguments = arguments != null ? new KernelFunctionArguments(arguments) : new KernelFunctionArguments();
}
public KernelFunction getFunction() {
return function;
}
@Nullable
public KernelArguments getArguments() {
@SuppressFBWarnings("EI_EXPOSE_REP")
public KernelFunctionArguments getArguments() {
return arguments;
}
}
@@ -1,16 +1,18 @@
package com.microsoft.semantickernel.hooks;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokedHook;
import com.microsoft.semantickernel.hooks.KernelHook.FunctionInvokingHook;
import com.microsoft.semantickernel.hooks.KernelHook.PreChatCompletionHook;
import com.microsoft.semantickernel.hooks.KernelHook.PromptRenderedHook;
import com.microsoft.semantickernel.hooks.KernelHook.PromptRenderingHook;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Function;
import javax.annotation.Nullable;
public class KernelHooks {
@@ -21,17 +23,21 @@ public class KernelHooks {
}
public KernelHooks(@Nullable KernelHooks kernelHooks) {
if (kernelHooks == null) {
this.hooks = new HashMap<>();
} else {
this.hooks = new HashMap<>(kernelHooks.getHooks());
this();
if (kernelHooks != null) {
this.hooks.putAll(kernelHooks.getHooks());
}
}
public KernelHooks(Map<String, KernelHook<?>> hooks) {
this.hooks = new HashMap<>(hooks);
this();
this.hooks.putAll(hooks);
}
public UnmodifiableKernelHooks unmodifiableClone() {
return new UnmodifiableKernelHooks(this);
}
private Map<String, KernelHook<?>> getHooks() {
return Collections.unmodifiableMap(hooks);
}
@@ -42,7 +48,7 @@ public class KernelHooks {
}
public String addFunctionInvokedHook(
Function<FunctionInvokedEvent, FunctionInvokedEvent> function) {
Function<FunctionInvokedEvent<?>, FunctionInvokedEvent<?>> function) {
return addHook((FunctionInvokedHook) function::apply);
}
@@ -61,9 +67,11 @@ public class KernelHooks {
return addHook((PromptRenderingHook) function::apply);
}
@SuppressWarnings("unchecked")
public <T extends KernelHookEvent> T executeHooks(T event) {
for (KernelHook<?> hook : hooks.values()) {
if (hook.test(event)) {
// unchecked cast
event = ((KernelHook<T>) hook).apply(event);
}
}
@@ -83,11 +91,70 @@ public class KernelHooks {
return hooks.remove(hookName);
}
public KernelHooks append(KernelHooks kernelHooks) {
Map<String, KernelHook<?>> newHooks = new HashMap<>(this.hooks);
newHooks.putAll(this.hooks);
newHooks.putAll(kernelHooks.getHooks());
public KernelHooks append(@Nullable KernelHooks kernelHooks) {
if (kernelHooks == null) {
return this;
}
hooks.putAll(kernelHooks.getHooks());
return new KernelHooks(newHooks);
return this;
}
public boolean isEmpty() {
return hooks.isEmpty();
}
public static class UnmodifiableKernelHooks extends KernelHooks {
private UnmodifiableKernelHooks(KernelHooks kernelHooks) {
super(kernelHooks);
}
@Override
public String addFunctionInvokingHook(Function<FunctionInvokingEvent, FunctionInvokingEvent> function) {
throw new UnsupportedOperationException("unmodifiable instance of KernelHooks");
}
@Override
public String addFunctionInvokedHook(Function<FunctionInvokedEvent<?>, FunctionInvokedEvent<?>> function) {
throw new UnsupportedOperationException("unmodifiable instance of KernelHooks");
}
@Override
public String addPreChatCompletionHook(Function<PreChatCompletionEvent, PreChatCompletionEvent> function) {
throw new UnsupportedOperationException("unmodifiable instance of KernelHooks");
}
@Override
public String addPromptRenderedHook(Function<PromptRenderedEvent, PromptRenderedEvent> function) {
throw new UnsupportedOperationException("unmodifiable instance of KernelHooks");
}
@Override
public String addPromptRenderingHook(Function<PromptRenderingEvent, PromptRenderingEvent> function) {
throw new UnsupportedOperationException("unmodifiable instance of KernelHooks");
}
@Override
public String addHook(KernelHook<?> hook) {
throw new UnsupportedOperationException("unmodifiable instance of KernelHooks");
}
@Override
public String addHook(String hookName, KernelHook<?> hook) {
throw new UnsupportedOperationException("unmodifiable instance of KernelHooks");
}
@Override
public KernelHooks append(@Nullable KernelHooks kernelHooks) {
throw new UnsupportedOperationException("unmodifiable instance of KernelHooks");
}
@Override
public KernelHook<?> removeHook(String hookName) {
throw new UnsupportedOperationException("unmodifiable instance of KernelHooks");
}
}
}
@@ -1,18 +1,20 @@
package com.microsoft.semantickernel.hooks;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
public class PromptRenderedEvent implements KernelHookEvent {
private final KernelFunction function;
private final KernelArguments arguments;
private final KernelFunctionArguments arguments;
private final String prompt;
public PromptRenderedEvent(KernelFunction function, KernelArguments arguments,
public PromptRenderedEvent(KernelFunction function, KernelFunctionArguments arguments,
String prompt) {
this.function = function;
this.arguments = arguments;
this.arguments = arguments != null ? new KernelFunctionArguments(arguments) : new KernelFunctionArguments();
this.prompt = prompt;
}
@@ -20,10 +22,12 @@ public class PromptRenderedEvent implements KernelHookEvent {
return function;
}
public KernelArguments getArguments() {
@SuppressFBWarnings("EI_EXPOSE_REP")
public KernelFunctionArguments getArguments() {
return arguments;
}
@SuppressFBWarnings("EI_EXPOSE_REP")
public String getPrompt() {
return prompt;
}
@@ -1,23 +1,26 @@
package com.microsoft.semantickernel.hooks;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
public class PromptRenderingEvent implements KernelHookEvent {
private final KernelFunction function;
private final KernelArguments arguments;
private final KernelFunctionArguments arguments;
public PromptRenderingEvent(KernelFunction function, KernelArguments arguments) {
public PromptRenderingEvent(KernelFunction function, KernelFunctionArguments arguments) {
this.function = function;
this.arguments = arguments;
this.arguments = arguments != null ? new KernelFunctionArguments(arguments) : new KernelFunctionArguments();
}
public KernelFunction getFunction() {
return function;
}
public KernelArguments getArguments() {
@SuppressFBWarnings("EI_EXPOSE_REP")
public KernelFunctionArguments getArguments() {
return arguments;
}
}
@@ -1,71 +0,0 @@
package com.microsoft.semantickernel.orchestration;
import com.microsoft.semantickernel.Todo;
import java.util.Collections;
import java.util.Map;
import javax.annotation.Nullable;
public abstract class DefaultKernelFunction implements KernelFunction {
/// <summary>
/// Gets the metadata describing the function.
/// </summary>
/// <returns>An instance of <see cref="KernelFunctionMetadata"/> describing the function</returns>
private final KernelFunctionMetadata metadata;
/// <summary>
/// Gets the prompt execution settings.
/// </summary>
@Nullable
private final Map<String, PromptExecutionSettings> executionSettings;
protected DefaultKernelFunction(
KernelFunctionMetadata metadata,
@Nullable
Map<String, PromptExecutionSettings> executionSettings) {
this.metadata = metadata;
this.executionSettings = executionSettings;
}
@Override
public KernelFunctionMetadata getMetadata() {
return metadata;
}
@Override
public String getSkillName() {
return metadata.getName();
}
@Override
public String getName() {
return metadata.getName();
}
@Override
@Nullable
public String getDescription() {
return metadata.getDescription();
}
@Override
public String toEmbeddingString() {
throw new Todo();
}
@Override
public String toManualString(boolean includeOutputs) {
throw new Todo();
}
@Override
@Nullable
public Map<String, PromptExecutionSettings> getExecutionSettings() {
if (executionSettings != null) {
return Collections.unmodifiableMap(executionSettings);
} else {
return null;
}
}
}
@@ -0,0 +1,99 @@
package com.microsoft.semantickernel.orchestration;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.hooks.KernelHooks.UnmodifiableKernelHooks;
import com.microsoft.semantickernel.orchestration.ToolCallBehavior.UnmodifiableToolCallBehavior;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Context passed to a Kernel or KernelFunction invoke
*/
public class InvocationContext implements Buildable {
private final UnmodifiableKernelHooks hooks;
private final PromptExecutionSettings promptExecutionSettings;
private final UnmodifiableToolCallBehavior toolCallBehavior;
public InvocationContext(
@Nullable KernelHooks hooks,
@Nullable PromptExecutionSettings promptExecutionSettings,
@Nullable ToolCallBehavior toolCallBehavior) {
this.hooks = unmodifiableClone(hooks);
this.promptExecutionSettings = promptExecutionSettings;
this.toolCallBehavior = unmodifiableClone(toolCallBehavior);
}
@SuppressFBWarnings(value="EI_EXPOSE_REP", justification="returns UnmodifiableKernelHooks")
@Nullable
public UnmodifiableKernelHooks getKernelHooks() {
return hooks;
}
@Nullable
public PromptExecutionSettings getPromptExecutionSettings() {
return promptExecutionSettings;
}
@SuppressFBWarnings(value="EI_EXPOSE_REP", justification="returns UnmodifiableToolCallBehavior")
@Nullable
public UnmodifiableToolCallBehavior getToolCallBehavior() {
return toolCallBehavior;
}
public static Builder builder() {
return new Builder();
}
private static UnmodifiableToolCallBehavior unmodifiableClone(ToolCallBehavior toolCallBehavior) {
if (toolCallBehavior instanceof UnmodifiableToolCallBehavior) {
return (UnmodifiableToolCallBehavior) toolCallBehavior;
} else if (toolCallBehavior != null) {
return toolCallBehavior.unmodifiableClone();
} else {
return null;
}
}
private static UnmodifiableKernelHooks unmodifiableClone(KernelHooks kernelHooks) {
if (kernelHooks instanceof UnmodifiableKernelHooks) {
return (UnmodifiableKernelHooks) kernelHooks;
} else if (kernelHooks != null) {
return kernelHooks.unmodifiableClone();
} else {
return null;
}
}
public static class Builder implements SemanticKernelBuilder<InvocationContext> {
private UnmodifiableKernelHooks hooks;
private PromptExecutionSettings promptExecutionSettings;
private UnmodifiableToolCallBehavior toolCallBehavior;
public Builder withKernelHooks(KernelHooks hooks) {
this.hooks = unmodifiableClone(hooks);
return this;
}
public Builder withPromptExecutionSettings(PromptExecutionSettings promptExecutionSettings) {
this.promptExecutionSettings = promptExecutionSettings;
return this;
}
public Builder withToolCallBehavior(ToolCallBehavior toolCallBehavior) {
this.toolCallBehavior = unmodifiableClone(toolCallBehavior);
return this;
}
@Override
public InvocationContext build() {
return new InvocationContext(hooks, promptExecutionSettings, toolCallBehavior);
}
}
}
@@ -1,51 +1,87 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.orchestration;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.Todo;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.semanticfunctions.InputVariable;
import com.microsoft.semantickernel.semanticfunctions.OutputVariable;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateFactory;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import reactor.core.publisher.Mono;
/**
* Semantic Kernel callable function interface
*
* @apiNote Breaking change: s/SKFunction<RequestConfiguration>/SKFunction/
* @param <T> The type of the result of the function
*/
public interface KernelFunction extends Buildable {
// TODO: add example of using ContextVariableType to class documentation
public abstract class KernelFunction<T> implements Buildable {
/// <summary>
/// Gets the metadata describing the function.
/// </summary>
/// <returns>An instance of <see cref="KernelFunctionMetadata"/> describing the function</returns>
private final KernelFunctionMetadata metadata;
/// <summary>
/// Gets the prompt execution settings.
/// </summary>
@Nullable
private final Map<String, PromptExecutionSettings> executionSettings;
protected KernelFunction(
KernelFunctionMetadata metadata,
@Nullable
Map<String, PromptExecutionSettings> executionSettings) {
this.metadata = metadata;
this.executionSettings = new HashMap<>();
if (executionSettings != null) {
this.executionSettings.putAll(executionSettings);
}
}
/**
* @return The name of the skill that this function is within
*/
String getSkillName();
public String getSkillName() {
return metadata.getName();
}
/**
* @return The name of this function
*/
String getName();
public String getName() {
return metadata.getName();
}
/**
* @return A description of the function
*/
@Nullable
String getDescription();
public String getDescription() {
return metadata.getDescription();
}
/**
* Create a string for generating an embedding for a function.
*
* @return A string for generating an embedding for a function.
*/
String toEmbeddingString();
public String toEmbeddingString() {
throw new Todo();
}
/**
* Create a manual-friendly string for a function.
@@ -53,68 +89,121 @@ public interface KernelFunction extends Buildable {
* @param includeOutputs Whether to include function outputs in the string.
* @return A manual-friendly string for a function.
*/
String toManualString(boolean includeOutputs);
public String toManualString(boolean includeOutputs) {
throw new Todo();
}
public Map<String, PromptExecutionSettings> getExecutionSettings() {
return Collections.unmodifiableMap(executionSettings);
}
KernelFunctionMetadata getMetadata();
public KernelFunctionMetadata getMetadata() {
return metadata;
}
@Deprecated
default Class<?> getType() {
throw new UnsupportedOperationException("Deprecated");
/**
* Invokes this KernelFunction. This is the most typical use case.
*
* @param kernel The Kernel containing services, plugins, and other state for
* use throughout the operation.
* @param arguments The arguments to pass to the function's invocation
* @return The result of the function's execution.
* @see FunctionResult#getResultVariable()
*/
public Mono<FunctionResult<T>> invokeAsync(
Kernel kernel,
@Nullable KernelFunctionArguments arguments) {
return invokeAsync(kernel, arguments, null);
}
/**
* Invokes this KernelFunction. If the {@code variableType} parameter is provided,
* the {@link ContextVarialbeType} is used to convert the result of the function to the
* the appropriate {@link FunctionResultType}. The {@code variableType} is
* not required for converting well-known types such as {@link String} and {@link Integer}
* which have pre-defined {@code ContextVariableType}s.
*
* @param kernel The Kernel containing services, plugins, and other state for
* use throughout the operation.
* @param arguments The arguments to pass to the function's invocation
* @param variableType The type of the {@link ContextVariable} returned in the {@link FunctionResult}
* @return The result of the function's execution.
* @see FunctionResult#getResultVariable()
* @see ContextVariableTypes#getDefaultVariableTypeForClass(Class)
*/
public Mono<FunctionResult<T>> invokeAsync(
Kernel kernel,
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> variableType) {
return invokeAsync(kernel, arguments, variableType, null);
}
/**
* Invokes the <see cref="KernelFunction"/>.
* Invokes this KernelFunction.
* <p>
* If the {@code variableType} parameter is provided,
* the {@link ContextVarialbeType} is used to convert the result of the function to the
* the appropriate {@link FunctionResultType}. The {@code variableType} is
* not required for converting well-known types such as {@link String} and {@link Integer}
* which have pre-defined {@code ContextVariableType}s.
* <p>
* The {@link InvocationContext} allows for customization of the
* behavior of function, including the ability to pass in {@link KernelHooks}
* {@link PromptExecutionSettings}, and {@link ToolCallBehavior}.
* <p>
* The difference between calling the {@code KernelFunction.invokeAsync} method
* directly and calling the {@code Kernel.invokeAsync} method is that the latter
* adds the {@link KernelHooks#getGlobalHooks() global KernelHooks} (if any)
* to the {@link InvocationContext}. Calling {@code KernelFunction.invokeAsync}
* directly does not add the global hooks.
*
* @param kernel The <see cref="Kernel"/> containing services, plugins, and other state for
* @param kernel The Kernel containing services, plugins, and other state for
* use throughout the operation.
* @param arguments The arguments to pass to the function's invocation, including any
* {@link PromptExecutionSettings}.
* @param <T> The type of the context variable
* @param arguments The arguments to pass to the function's invocation
* @param variableType The type of the {@link ContextVariable} returned in the {@link FunctionResult}
* @param invocationContext The arguments to pass to the function's invocation
* @return The result of the function's execution.
*/
<T> Mono<FunctionResult<T>> invokeAsync(
* @see FunctionResult#getResultVariable()
*/
public abstract Mono<FunctionResult<T>> invokeAsync(
Kernel kernel,
@Nullable KernelArguments arguments,
@Nullable ContextVariableType<T> variableType);
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> variableType,
@Nullable InvocationContext invocationContext);
<T> Mono<FunctionResult<T>> invokeAsync(
Kernel kernel,
@Nullable KernelArguments arguments,
KernelHooks kernelHooks,
@Nullable ContextVariableType<T> variableType);
public static interface FromPromptBuilder<T> {
@Nullable
Map<String, PromptExecutionSettings> getExecutionSettings();
FromPromptBuilder<T> withName(@Nullable String name);
interface FromPromptBuilder {
FromPromptBuilder withName(@Nullable String name);
FromPromptBuilder withInputParameters(
FromPromptBuilder<T> withInputParameters(
@Nullable List<InputVariable> inputVariables);
FromPromptBuilder withPromptTemplate(
FromPromptBuilder<T> withPromptTemplate(
@Nullable PromptTemplate promptTemplate);
FromPromptBuilder withExecutionSettings(
FromPromptBuilder<T> withExecutionSettings(
@Nullable
Map<String, PromptExecutionSettings> executionSettings);
FromPromptBuilder withDefaultExecutionSettings(
FromPromptBuilder<T> withDefaultExecutionSettings(
@Nullable
PromptExecutionSettings executionSettings);
FromPromptBuilder withDescription(@Nullable String description);
FromPromptBuilder<T> withDescription(@Nullable String description);
FromPromptBuilder withTemplate(@Nullable String template);
FromPromptBuilder<T> withTemplate(@Nullable String template);
KernelFunction build();
KernelFunction<T> build();
FromPromptBuilder withTemplateFormat(String templateFormat);
FromPromptBuilder<T> withTemplateFormat(String templateFormat);
FromPromptBuilder withOutputVariable(@Nullable OutputVariable outputVariable);
FromPromptBuilder<T> withOutputVariable(@Nullable OutputVariable outputVariable);
FromPromptBuilder withPromptTemplateFactory(
FromPromptBuilder<T> withOutputVariable(@Nullable String description, String type);
FromPromptBuilder<T> withPromptTemplateFactory(
@Nullable PromptTemplateFactory promptTemplateFactory);
}
}
@@ -0,0 +1,249 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.orchestration;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.exceptions.SKException;
import com.microsoft.semantickernel.orchestration.contextvariables.CaseInsensitiveMap;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import reactor.util.annotation.NonNull;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
/**
* Context Variables is a data structure that holds temporary data while a task is being performed.
* It is accessed by functions in the pipeline.
*/
public class KernelFunctionArguments implements Buildable, Map<String, ContextVariable<?>> {
/**
* Default key for the main input.
*/
public static final String MAIN_KEY = "input";
private final CaseInsensitiveMap<ContextVariable<?>> variables;
public KernelFunctionArguments(
Map<String, ContextVariable<?>> variables) {
this.variables = new CaseInsensitiveMap<>(variables);
}
public KernelFunctionArguments(@NonNull ContextVariable<?> content) {
this.variables = new CaseInsensitiveMap<>();
this.variables.put(MAIN_KEY, content);
}
public KernelFunctionArguments() {
this.variables = new CaseInsensitiveMap<>();
}
/**
* Get the input (entry in the MAIN_KEY slot)
*
* @return input
*/
@Nullable
public ContextVariable<?> getInput() {
return get(MAIN_KEY);
}
/**
* Create formatted string of the variables
*
* @return formatted string
*/
public String prettyPrint() {
return variables.entrySet().stream()
.reduce(
"",
(str, entry) ->
str
+ System.lineSeparator()
+ entry.getKey()
+ ": "
+ entry.getValue(),
(a, b) -> a + b);
}
/**
* Return the variable with the given name
*
* @param key variable name
* @return content of the variable
*/
@Nullable
public ContextVariable<?> get(String key) {
return variables.get(key);
}
/**
* Return the variable with the given name
*
* @param key variable name
* @return content of the variable
*/
@Nullable
<T> ContextVariable<T> get(String key, Class<T> clazz) {
ContextVariable<?> value = variables.get(key);
if (value == null) {
return null;
} else if (clazz.isAssignableFrom(value.getType().getClazz())) {
return (ContextVariable<T>) value;
}
throw new IllegalArgumentException(
String.format(
"Variable %s is of type %s, but requested type is %s",
key, value.getType().getClazz(), clazz));
}
public boolean isNullOrEmpty(String key) {
return get(key) == null || get(key).isEmpty();
}
@Override
public int size() {
return variables.size();
}
@Override
public boolean isEmpty() {
return variables.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return variables.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return variables.containsValue(value);
}
@Override
public ContextVariable<?> get(Object key) {
return variables.get(key);
}
@Override
public ContextVariable<?> put(String key, ContextVariable<?> value) {
return variables.put(key, value);
}
@Override
public ContextVariable<?> remove(Object key) {
return variables.remove(key);
}
@Override
public void putAll(Map<? extends String, ? extends ContextVariable<?>> m) {
variables.putAll(m);
}
@Override
public void clear() {
variables.clear();
}
@Override
public Set<String> keySet() {
return variables.keySet();
}
@Override
public Collection<ContextVariable<?>> values() {
return variables.values();
}
@Override
public Set<Entry<String, ContextVariable<?>>> entrySet() {
return variables.entrySet();
}
public static Builder builder() {
return new KernelFunctionArguments.Builder();
}
/**
* Builder for ContextVariables
*/
public static class Builder implements SemanticKernelBuilder<KernelFunctionArguments> {
private final Map<String,ContextVariable<?>> variables;
public Builder() {
variables = new HashMap<>();
this.variables.put(MAIN_KEY, ContextVariable.of(""));
}
/**
* Builds an instance with the given content in the default main key
*
* @param content Entry to place in the "input" slot
* @return {$code this} Builder for fluent coding
*/
public <T> Builder withInput(ContextVariable<T> content) {
return withVariable(MAIN_KEY, content);
}
/**
* Builds an instance with the given content in the default main key
*
* @param content Entry to place in the "input" slot
* @return {$code this} Builder for fluent coding
* @throws SKException if the content cannot be converted to a ContextVariable
*/
public Builder withInput(Object content) {
return withInput(ContextVariable.of(content));
}
/**
* Builds an instance with the given variables
*
* @param map Existing variables
* @return {$code this} Builder for fluent coding
*/
public Builder withVariables(Map<String, ContextVariable<?>> map) {
variables.putAll(map);
return this;
}
/**
* Set variable
*
* @param key variable name
* @param value variable value
* @return {$code this} Builder for fluent coding
*/
public <T> Builder withVariable(String key, ContextVariable<T> value) {
variables.put(key, value);
return this;
}
/**
* Set variable
*
* @param key variable name
* @param value variable value
* @return {$code this} Builder for fluent coding
* @throws SKException if the value cannot be converted to a ContextVariable
*/
public Builder withVariable(String key, Object value) {
return withVariable(key, ContextVariable.of(value));
}
@Override
public KernelFunctionArguments build() {
return new KernelFunctionArguments(variables);
}
}
}
@@ -1,13 +1,15 @@
package com.microsoft.semantickernel.orchestration;
import com.microsoft.semantickernel.plugin.KernelParameterMetadata;
import com.microsoft.semantickernel.plugin.KernelReturnParameterMetadata;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
public class KernelFunctionMetadata {
import com.microsoft.semantickernel.plugin.KernelParameterMetadata;
import com.microsoft.semantickernel.plugin.KernelReturnParameterMetadata;
public class KernelFunctionMetadata<T> {
/// <summary>The name of the function.</summary>
private final String name;
@@ -19,7 +21,7 @@ public class KernelFunctionMetadata {
/// <summary>The function's return parameter.</summary>
private final KernelReturnParameterMetadata<?> returnParameter;
private final KernelReturnParameterMetadata<T> returnParameter;
public KernelFunctionMetadata(
@@ -28,7 +30,7 @@ public class KernelFunctionMetadata {
String description,
@Nullable
List<KernelParameterMetadata<?>> parameters,
KernelReturnParameterMetadata<?> returnParameter) {
KernelReturnParameterMetadata<T> returnParameter) {
this.name = name;
this.description = description;
if (parameters == null) {
@@ -53,7 +55,7 @@ public class KernelFunctionMetadata {
return description;
}
public KernelReturnParameterMetadata<?> getReturnParameter() {
public KernelReturnParameterMetadata<T> getReturnParameter() {
return returnParameter;
}
}
@@ -23,7 +23,7 @@ public class KernelFunctionYaml {
/// <param name="promptTemplateFactory">>Prompt template factory.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to use for logging. If null, no logging will be performed.</param>
/// <returns>The created <see cref="KernelFunction"/>.</returns>
public static KernelFunction fromPromptYaml(
public static <T> KernelFunction<T> fromPromptYaml(
String yaml,
@Nullable PromptTemplateFactory promptTemplateFactory
) throws IOException {
@@ -31,20 +31,21 @@ public class KernelFunctionYaml {
return fromYaml(targetStream, promptTemplateFactory);
}
public static KernelFunction fromPromptYaml(
public static <T> KernelFunction<T> fromPromptYaml(
String yaml
) throws IOException {
InputStream targetStream = new ByteArrayInputStream(yaml.getBytes(StandardCharsets.UTF_8));
return fromYaml(targetStream, null);
}
public static KernelFunction fromYaml(Path filePath) throws IOException {
public static <T> KernelFunction<T> fromYaml(Path filePath) throws IOException {
InputStream inputStream = Thread.currentThread().getContextClassLoader()
.getResourceAsStream(filePath.toString());
return fromYaml(inputStream, null);
}
private static KernelFunction fromYaml(
@SuppressWarnings("unchecked")
private static <T> KernelFunction<T> fromYaml(
InputStream inputStream,
@Nullable PromptTemplateFactory promptTemplateFactory
) throws IOException {
@@ -59,7 +60,7 @@ public class KernelFunctionYaml {
promptTemplate = promptTemplateFactory.tryCreate(functionModel);
}
return new KernelFunctionFromPrompt.Builder()
return (KernelFunction<T>)new KernelFunctionFromPrompt.Builder()
.withName(functionModel.getName())
.withInputParameters(functionModel.getInputVariables())
.withPromptTemplate(promptTemplate)
@@ -1,12 +1,14 @@
package com.microsoft.semantickernel.orchestration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.plugin.KernelParameterMetadata;
import com.microsoft.semantickernel.plugin.KernelReturnParameterMetadata;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromMethod.ImplementationFunc;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
public class MethodDetails {
@@ -1,7 +1,6 @@
package com.microsoft.semantickernel.orchestration;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.Collections;
@@ -56,8 +55,6 @@ public class PromptExecutionSettings {
private final String user;
@Nullable
private final List<String> stopSequences;
@Nullable
private final ToolCallBehavior toolCallBehavior;
/// <summary>
/// Modify the likelihood of specified tokens appearing in the completion.
@@ -81,36 +78,6 @@ public class PromptExecutionSettings {
@JsonProperty(STOP_SEQUENCES) List<String> stopSequences,
@Nullable
@JsonProperty(TOKEN_SELECTION_BIASES) Map<Integer, Integer> tokenSelectionBiases) {
this(
serviceId,
modelId,
temperature,
topP,
presencePenalty,
frequencyPenalty,
maxTokens,
resultsPerPrompt,
bestOf,
user,
stopSequences,
tokenSelectionBiases,
null);
}
public PromptExecutionSettings(
String serviceId,
String modelId,
double temperature,
double topP,
double presencePenalty,
double frequencyPenalty,
int maxTokens,
int resultsPerPrompt,
int bestOf,
String user,
@Nullable List<String> stopSequences,
@Nullable Map<Integer, Integer> tokenSelectionBiases,
@Nullable ToolCallBehavior toolCallBehavior) {
this.serviceId = serviceId;
this.modelId = modelId;
this.temperature = temperature;
@@ -126,8 +93,6 @@ public class PromptExecutionSettings {
this.tokenSelectionBiases =
tokenSelectionBiases != null ? new HashMap<>(tokenSelectionBiases)
: Collections.emptyMap();
this.toolCallBehavior =
toolCallBehavior != null ? new ToolCallBehavior(toolCallBehavior) : null;
}
@JsonProperty(SERVICE_ID)
@@ -199,15 +164,6 @@ public class PromptExecutionSettings {
return null;
}
@JsonIgnore
@Nullable
public ToolCallBehavior getToolCallBehavior() {
if (toolCallBehavior != null) {
return new ToolCallBehavior(toolCallBehavior);
}
return null;
}
public static Builder builder() {
return new Builder();
}
@@ -275,11 +231,6 @@ public class PromptExecutionSettings {
return this;
}
public Builder withToolCallBehavior(ToolCallBehavior toolCallBehavior) {
settings.put("toolCallBehavior", toolCallBehavior);
return this;
}
@SuppressWarnings("unchecked")
public Builder withStopSequences(List<String> stopSequences) {
if (stopSequences != null) {
@@ -313,8 +264,7 @@ public class PromptExecutionSettings {
(String) settings.getOrDefault(USER, ""),
(List<String>) settings.getOrDefault(STOP_SEQUENCES, Collections.emptyList()),
(Map<Integer, Integer>) settings.getOrDefault(TOKEN_SELECTION_BIASES,
Collections.emptyMap()),
(ToolCallBehavior) settings.getOrDefault("toolCallBehavior", new ToolCallBehavior())
Collections.emptyMap())
);
}
}
@@ -12,12 +12,10 @@ public class ToolCallBehavior {
private static class FunctionCallBehavior {
private final String key;
private final boolean required;
private final boolean enabled;
FunctionCallBehavior(KernelFunction function, boolean required, boolean enabled) {
this.key = getKey(function);
this.required = required;
this.enabled = enabled;
}
@@ -52,6 +50,10 @@ public class ToolCallBehavior {
settings.putAll(toolCallBehavior.settings);
}
public UnmodifiableToolCallBehavior unmodifiableClone() {
return new UnmodifiableToolCallBehavior(this);
}
public ToolCallBehavior kernelFunctions(boolean enable) {
setFlag("kernelFunctions", enable);
return this;
@@ -161,4 +163,42 @@ public class ToolCallBehavior {
return settings.getOrDefault(key, defaultValue);
}
public static class UnmodifiableToolCallBehavior extends ToolCallBehavior {
protected UnmodifiableToolCallBehavior(ToolCallBehavior toolCallBehavior) {
super(toolCallBehavior);
}
@Override
public final ToolCallBehavior kernelFunctions(boolean enable) {
throw new UnsupportedOperationException("unmodifiable instance of ToolCallBehavior");
}
@Override
public final ToolCallBehavior autoInvoke(boolean enable) {
throw new UnsupportedOperationException("unmodifiable instance of ToolCallBehavior");
}
@Override
public final ToolCallBehavior requireFunction(KernelFunction function, boolean require) {
throw new UnsupportedOperationException("unmodifiable instance of ToolCallBehavior");
}
@Override
public final ToolCallBehavior enableFunction(KernelFunction function, boolean enable) {
throw new UnsupportedOperationException("unmodifiable instance of ToolCallBehavior");
}
@Override
protected final void setFlag(String key, boolean value) {
throw new UnsupportedOperationException("unmodifiable instance of ToolCallBehavior");
}
@Override
protected final void setSetting(String key, int value) {
throw new UnsupportedOperationException("unmodifiable instance of ToolCallBehavior");
}
}
}
@@ -1,9 +1,12 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.orchestration.contextvariables;
import java.util.Objects;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.exceptions.SKException;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter.NoopConverter;
import javax.annotation.Nullable;
public class ContextVariable<T> {
@@ -28,6 +31,7 @@ public class ContextVariable<T> {
return of(t);
}
@SuppressWarnings("rawtypes")
public static ContextVariable<?> untypedOf(
@Nullable Object value,
Class<?> clazz) {
@@ -141,10 +145,10 @@ public class ContextVariable<T> {
@Nullable
public <U> U getValue(Class<U> clazz) {
if (value == null || clazz.isAssignableFrom(value.getClass())) {
try {
return clazz.cast(value);
} else {
throw new RuntimeException("Cannot cast " + value.getClass() + " to " + clazz);
} catch (ClassCastException e) {
throw new SKException("Cannot cast " + (value != null ? value.getClass() : "null") + " to " + clazz, e);
}
}
@@ -171,12 +175,20 @@ public class ContextVariable<T> {
@SuppressWarnings("unchecked")
public static <T> ContextVariable<T> of(T value) {
Objects.requireNonNull(value, "value cannot be null");
if (value instanceof ContextVariable) {
return (ContextVariable<T>) value;
}
ContextVariableType<T> type = ContextVariableTypes.getDefaultVariableTypeForClass(
(Class<T>) value.getClass());
return new ContextVariable<>(type, value);
}
public static <T> ContextVariable<T> of(T value, ContextVariableTypeConverter<T> converter) {
Objects.requireNonNull(value, "value cannot be null");
Objects.requireNonNull(converter, "converter cannot be null");
ContextVariableType<T> type = new ContextVariableType<>(converter, converter.getType());
return new ContextVariable<>(type, value);
}
@@ -39,4 +39,5 @@ public class ContextVariableType<T> {
ContextVariableTypeConverter<T> converter = getConverter();
return ContextVariable.of(converter.getType(), converter.fromObject(it));
}
}
@@ -5,7 +5,9 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -1,5 +1,15 @@
package com.microsoft.semantickernel.orchestration.contextvariables;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.exceptions.SKException;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter.NoopConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.converters.BooleanVariableContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.converters.CharacterVariableContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.converters.ChatHistoryVariableContextVariableTypeConverter;
@@ -9,11 +19,6 @@ import com.microsoft.semantickernel.orchestration.contextvariables.converters.In
import com.microsoft.semantickernel.orchestration.contextvariables.converters.NumberVariableContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.converters.StringVariableContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.converters.VoidVariableContextVariableTypeConverter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
public class ContextVariableTypes {
@@ -82,11 +87,11 @@ public class ContextVariableTypes {
}
}
public static <T> ContextVariableType<T> getDefaultVariableTypeForClass(Class<T> aClass) {
return DEFAULT_TYPES.getVariableTypeForClass(aClass);
}
@SuppressWarnings("unchecked")
public <T> ContextVariableType<T> getVariableTypeForClass(Class<T> aClass) {
ContextVariableType<?> contextVariableType = variableTypes.get(aClass);
@@ -102,9 +107,10 @@ public class ContextVariableTypes {
})
.findFirst()
.orElseThrow(
() -> new RuntimeException("Unknown context variable type: " + aClass.getName()));
() -> new SKException("Unknown context variable type: " + aClass.getName()));
}
@SuppressWarnings("unchecked")
public <T> ContextVariableType<T> getVariableTypeForSuperClass(Class<T> aClass) {
ContextVariableType<?> contextVariableType = variableTypes.get(aClass);
@@ -120,6 +126,6 @@ public class ContextVariableTypes {
})
.findFirst()
.orElseThrow(
() -> new RuntimeException("Unknown context variable type: " + aClass.getName()));
() -> new SKException("Unknown context variable type: " + aClass.getName()));
}
}
@@ -1,283 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.orchestration.contextvariables;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import reactor.util.annotation.NonNull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/// <summary>
/// Context Variables is a data structure that holds temporary data while a task is being performed.
/// It is accessed and manipulated by functions in the pipeline.
/// </summary>
public class DefaultKernelArguments implements KernelArguments, WritableKernelArguments {
private final CaseInsensitiveMap<ContextVariable<?>> variables;
private final Map<String, PromptExecutionSettings> executionSettings;
/// <summary>
/// In the simplest scenario, the data is an input string, stored here.
/// </summary>
// public string Input => this._variables[MainKey];
/// <summary>
/// Constructor for context variables.
/// </summary>
/// <param name="content">Optional value for the main variable of the context.</param>
DefaultKernelArguments(@NonNull ContextVariable<?> content) {
this.variables = new CaseInsensitiveMap<>();
this.variables.put(MAIN_KEY, content);
this.executionSettings = new HashMap<>();
}
public DefaultKernelArguments(
Map<String, ContextVariable<?>> variables,
@Nullable
PromptExecutionSettings executionSettings) {
this.variables = new CaseInsensitiveMap<>(variables);
this.executionSettings = new HashMap<>();
this.executionSettings.put(PromptExecutionSettings.DEFAULT_SERVICE_ID, executionSettings);
}
public DefaultKernelArguments() {
this.variables = new CaseInsensitiveMap<>();
this.executionSettings = new HashMap<>();
}
public DefaultKernelArguments(
Map<String, ContextVariable<?>> variables,
Map<String, PromptExecutionSettings> executionSettings) {
if (variables == null) {
this.variables = new CaseInsensitiveMap<>();
} else {
this.variables = new CaseInsensitiveMap<>(variables);
}
if (executionSettings == null) {
this.executionSettings = new HashMap<>();
} else {
this.executionSettings = new HashMap<>(executionSettings);
}
}
@Override
public KernelArguments setVariable(@NonNull String key, @NonNull ContextVariable<?> content) {
this.variables.put(key, content);
return this;
}
@Override
public KernelArguments setVariable(String key, Object content) {
this.variables.put(key, ContextVariable.of(content));
return this;
}
/// <summary>
/// Updates the main input text with the new value after a function is complete.
/// </summary>
/// <param name="content">The new input value, for the next function in the pipeline, or as a
// result for the user
/// if the pipeline reached the end.</param>
/// <returns>The current instance</returns>
@Override
public KernelArguments update(@NonNull ContextVariable<?> content) {
return setVariable(MAIN_KEY, content);
}
public DefaultKernelArguments update(@NonNull DefaultKernelArguments newData) {
return update(newData, true);
}
/// <summary>
/// Updates all the local data with new data, merging the two datasets.
/// Do not discard old data
/// </summary>
/// <param name="newData">New data to be merged</param>
/// <param name="merge">Whether to merge and keep old data, or replace. False == discard old
// data.</param>
/// <returns>The current instance</returns>
@Override
public DefaultKernelArguments update(@NonNull KernelArguments newData, boolean merge) {
this.variables.putAll(newData);
return this;
}
@Override
public KernelArguments remove(String key) {
variables.remove(key);
return this;
}
@Override
public WritableKernelArguments writableClone() {
return new DefaultKernelArguments(variables, executionSettings);
}
@Override
@Nullable
public ContextVariable<?> getInput() {
return get(MAIN_KEY);
}
@Override
public String prettyPrint() {
return variables.entrySet().stream()
.reduce(
"",
(str, entry) ->
str
+ System.lineSeparator()
+ entry.getKey()
+ ": "
+ entry.getValue(),
(a, b) -> a + b);
}
@Nullable
@Override
public <T> ContextVariable<T> get(String key, Class<T> clazz) {
ContextVariable<?> value = variables.get(key);
if (value == null) {
return null;
} else if (clazz.isAssignableFrom(value.getType().getClazz())) {
return (ContextVariable<T>) value;
}
throw new IllegalArgumentException(
String.format(
"Variable %s is of type %s, but requested type is %s",
key, value.getType().getClazz(), clazz));
}
@Nullable
@Override
public Map<String, PromptExecutionSettings> getExecutionSettings() {
return Collections.unmodifiableMap(executionSettings);
}
@Override
public boolean isNullOrEmpty(String key) {
return get(key) == null || get(key).isEmpty();
}
@Override
@Nullable
public ContextVariable<?> get(String key) {
return variables.get(key);
}
@Override
public int size() {
return variables.size();
}
@Override
public boolean isEmpty() {
return variables.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return variables.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return variables.containsValue(value);
}
@Override
@Nullable
public ContextVariable<?> get(Object key) {
return variables.get(key);
}
@Override
public ContextVariable<?> put(String key, ContextVariable<?> value) {
return variables.put(key, value);
}
@Override
public ContextVariable<?> remove(Object key) {
return variables.remove(key);
}
@Override
public void putAll(Map<? extends String, ? extends ContextVariable<?>> m) {
variables.putAll(m);
}
@Override
public void clear() {
variables.clear();
}
@Override
public Set<String> keySet() {
return variables.keySet();
}
@Override
public Collection<ContextVariable<?>> values() {
return variables.values();
}
@Override
public Set<Entry<String, ContextVariable<?>>> entrySet() {
return variables.entrySet();
}
public static class Builder implements KernelArguments.Builder {
private final DefaultKernelArguments variables;
private final Map<String, PromptExecutionSettings> executionSettings;
public Builder() {
variables = new DefaultKernelArguments();
this.variables.put(MAIN_KEY, ContextVariable.of(""));
executionSettings = new HashMap<>();
}
@Override
public <T> KernelArguments.Builder withVariable(String key, ContextVariable<T> value) {
variables.put(key, value);
return this;
}
@Override
public KernelArguments.Builder withVariable(String key, Object value) {
variables.put(key, ContextVariable.of(value));
return this;
}
@Override
public <T> Builder withInput(ContextVariable<T> content) {
variables.put(MAIN_KEY, content);
return this;
}
@Override
public KernelArguments.Builder withInput(Object content) {
return withInput(ContextVariable.of(content));
}
@Override
public Builder withVariables(Map<String, ContextVariable<?>> map) {
variables.putAll(map);
return this;
}
@Override
public KernelArguments build() {
return new DefaultKernelArguments(variables, executionSettings);
}
}
}
@@ -1,119 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.orchestration.contextvariables;
// Copyright (c) Microsoft. All rights reserved.
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import java.util.Map;
import javax.annotation.Nullable;
/**
* Context Variables is a data structure that holds temporary data while a task is being performed.
* It is accessed by functions in the pipeline.
*/
public interface KernelArguments extends Buildable, Map<String, ContextVariable<?>> {
/**
* Default key for the main input
*/
String MAIN_KEY = "input";
/**
* Get a clone of the variables that can be modified
*
* @return Writable clone of the variables
*/
WritableKernelArguments writableClone();
/**
* Get the input (entry in the MAIN_KEY slot)
*
* @return input
*/
@Nullable
ContextVariable<?> getInput();
/**
* Create formatted string of the variables
*
* @return formatted string
*/
String prettyPrint();
/**
* Return the variable with the given name
*
* @param key variable name
* @return content of the variable
*/
@Nullable
ContextVariable<?> get(String key);
/**
* Return the variable with the given name
*
* @param key variable name
* @return content of the variable
*/
@Nullable
<T> ContextVariable<T> get(String key, Class<T> clazz);
@Nullable
Map<String, PromptExecutionSettings> getExecutionSettings();
static Builder builder() {
return new DefaultKernelArguments.Builder();
}
boolean isNullOrEmpty(String key);
/**
* Builder for ContextVariables
*/
interface Builder extends SemanticKernelBuilder<KernelArguments> {
/**
* Builds an instance with the given content in the default main key
*
* @param content Entry to place in the "input" slot
* @return an instantiation of ContextVariables
*/
<T> Builder withInput(ContextVariable<T> content);
/**
* Builds an instance with the given content in the default main key
*
* @param content Entry to place in the "input" slot
* @return an instantiation of ContextVariables
*/
Builder withInput(Object content);
/**
* Builds an instance with the given variables
*
* @param map Existing variables
* @return an instantiation of ContextVariables
*/
Builder withVariables(Map<String, ContextVariable<?>> map);
/**
* Set variable
*
* @param key variable name
* @param value variable value
* @return builder for fluent chaining
*/
<T> Builder withVariable(String key, ContextVariable<T> value);
/**
* Set variable
*
* @param key variable name
* @param value variable value
* @return builder for fluent chaining
*/
Builder withVariable(String key, Object value);
}
}
@@ -1,53 +0,0 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.orchestration.contextvariables;
import java.util.Map;
/**
* Context Variables is a data structure that holds temporary data while a task is being performed.
* It is accessed by functions in the pipeline.
*/
public interface WritableKernelArguments extends KernelArguments {
/**
* Set the value
*
* @param key variable name
* @param content value to set
* @return Context for fluent calls
*/
KernelArguments setVariable(String key, ContextVariable<?> content);
KernelArguments setVariable(String key, Object content);
/**
* Updates the main input text with the new value after a function is complete.
*
* @param content The new input value, for the next function in the pipeline, or as a result for
* the user if the pipeline reached the end.
* @return The current instance
*/
KernelArguments update(ContextVariable<?> content);
/**
* Updates the variables merging or overwriting in the new values.
*
* @param newData Data to merge or overwrite.
* @param merge Whether to merge the new data with the existing data or to replace it
* @return The current instance
*/
KernelArguments update(KernelArguments newData, boolean merge);
KernelArguments remove(String key);
interface Builder {
/**
* Builds an instance with the given variables
*
* @param map Existing variables
* @return an instantiation of ContextVariables
*/
WritableKernelArguments build(Map<String, ContextVariable<?>> map);
}
}
@@ -1,5 +1,12 @@
package com.microsoft.semantickernel.plugin;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionFromMethod;
@@ -8,11 +15,6 @@ import com.microsoft.semantickernel.semanticfunctions.KernelPromptTemplateFactor
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;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
public class KernelFunctionFactory {
@@ -29,7 +31,7 @@ public class KernelFunctionFactory {
/// <param name="returnParameter">Optional return parameter description. If null, it will default to one derived from the method represented by <paramref name="method"/>.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to use for logging. If null, no logging will be performed.</param>
/// <returns>The created <see cref="KernelFunction"/> wrapper for <paramref name="method"/>.</returns>
public static KernelFunction createFromMethod(
public static <T> KernelFunction<T> createFromMethod(
Method method,
Object target,
@Nullable String functionName,
@@ -47,7 +49,7 @@ public class KernelFunctionFactory {
* @param promptTemplate Prompt template for the function.
* @return The created {@link KernelFunction} for invoking the prompt.
*/
public static KernelFunction createFromPrompt(String promptTemplate) {
public static <T> KernelFunction<T> createFromPrompt(String promptTemplate) {
return createFromPrompt(promptTemplate, null, null, null, null, null);
}
@@ -67,7 +69,7 @@ public class KernelFunctionFactory {
* default factory will be used.
* @return The created {@link KernelFunction} for invoking the prompt.
*/
public static KernelFunction createFromPrompt(
public static <T> KernelFunction<T> createFromPrompt(
String promptTemplate,
@Nullable PromptExecutionSettings executionSettings,
@Nullable String functionName,
@@ -83,7 +85,7 @@ public class KernelFunctionFactory {
promptTemplateFactory);
}
public static KernelFunction createFromPrompt(
public static <T> KernelFunction<T> createFromPrompt(
PromptTemplateConfig promptConfig,
@Nullable PromptTemplateFactory promptTemplateFactory) {
@@ -95,10 +97,10 @@ public class KernelFunctionFactory {
promptConfig);
}
public static KernelFunction create(
public static <T> KernelFunction<T> create(
PromptTemplate promptTemplate,
PromptTemplateConfig promptConfig) {
return new KernelFunctionFromPrompt(
return new KernelFunctionFromPrompt<>(
promptTemplate,
promptConfig,
null);
@@ -7,19 +7,19 @@ import java.util.Iterator;
import java.util.Map;
import javax.annotation.Nullable;
public class KernelPlugin implements Iterable<KernelFunction> {
public class KernelPlugin implements Iterable<KernelFunction<?>> {
private final String name;
@Nullable
private final String description;
private final CaseInsensitiveMap<KernelFunction> functions;
private final CaseInsensitiveMap<KernelFunction<?>> functions;
public KernelPlugin(
String name,
@Nullable
String description,
Map<String, KernelFunction> plugins) {
Map<String, KernelFunction<?>> plugins) {
this.name = name;
this.description = description;
this.functions = new CaseInsensitiveMap<>();
@@ -28,21 +28,22 @@ public class KernelPlugin implements Iterable<KernelFunction> {
}
}
public void addFunction(KernelFunction function) {
public void addFunction(KernelFunction<?> function) {
functions.put(function.getName(), function);
}
public Map<String, KernelFunction> getFunctions() {
public Map<String, KernelFunction<?>> getFunctions() {
return Collections.unmodifiableMap(functions);
}
@Nullable
public KernelFunction get(String functionName) {
return functions.get(functionName);
@SuppressWarnings("unchecked")
public <T> KernelFunction<T> get(String functionName) {
return (KernelFunction<T>) functions.get(functionName);
}
@Override
public Iterator<KernelFunction> iterator() {
public Iterator<KernelFunction<?>> iterator() {
return functions.values().iterator();
}
@@ -26,12 +26,12 @@ public class KernelPluginCollection implements Iterable<KernelPlugin> {
plugins.forEach(plugin -> this.plugins.put(plugin.getName(), plugin));
}
public KernelFunction getFunction(String pluginName, String functionName) {
public KernelFunction<?> getFunction(String pluginName, String functionName) {
KernelPlugin plugin = plugins.get(pluginName);
if (plugin == null) {
throw new IllegalArgumentException("Failed to find plugin " + pluginName);
}
KernelFunction function = plugin.get(functionName);
KernelFunction<?> function = plugin.get(functionName);
if (function == null) {
throw new IllegalArgumentException(
@@ -1,5 +1,25 @@
package com.microsoft.semantickernel.plugin;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.semantickernel.exceptions.SKException;
import com.microsoft.semantickernel.orchestration.KernelFunction;
@@ -13,22 +33,6 @@ import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateFactory;
import com.microsoft.semantickernel.util.EmbeddedResourceLoader;
import com.microsoft.semantickernel.util.EmbeddedResourceLoader.ResourceLocation;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class KernelPluginFactory {
@@ -47,7 +51,7 @@ public class KernelPluginFactory {
/// Attributed methods must all have different names; overloads are not supported.
/// </remarks>
public static KernelPlugin createFromObject(Object target, String pluginName) {
List<KernelFunction> methods = Arrays.stream(target.getClass().getMethods())
List<KernelFunction<?>> methods = Arrays.stream(target.getClass().getMethods())
.filter(method -> method.isAnnotationPresent(DefineKernelFunction.class))
.map(method -> {
DefineKernelFunction annotation = method.getAnnotation(DefineKernelFunction.class);
@@ -64,7 +68,7 @@ public class KernelPluginFactory {
annotation.description(),
getParameters(method),
kernelReturnParameterMetadata);
}).collect(Collectors.toList());
}).collect(ArrayList::new, (list, it) -> list.add(it), (a, b) -> a.addAll(b));
return createFromFunctions(pluginName, methods);
}
@@ -80,6 +84,11 @@ public class KernelPluginFactory {
+ ", this is an async method, It is required to add an annotation to specify the return type");
}
} else {
String className = annotation.returnType();
if (method.getReturnType().getName().equals(className)) {
// primarily meant to handle void
return method.getReturnType();
}
try {
returnType = Thread.currentThread().getContextClassLoader()
.loadClass(annotation.returnType());
@@ -110,7 +119,7 @@ public class KernelPluginFactory {
/// <exception cref="ArgumentException"><paramref name="functions"/> contains two functions with the same name.</exception>
public static KernelPlugin createFromFunctions(
String pluginName,
@Nullable List<KernelFunction> functions) {
@Nullable List<KernelFunction<?>> functions) {
return createFromFunctions(pluginName, null, functions);
}
@@ -123,10 +132,10 @@ public class KernelPluginFactory {
/// <exception cref="ArgumentNullException"><paramref name="functions"/> contains a null function.</exception>
/// <exception cref="ArgumentException"><paramref name="functions"/> contains two functions with the same name.</exception>
public static KernelPlugin createFromFunctions(String pluginName, @Nullable String description,
@Nullable List<KernelFunction> functions) {
Map<String, KernelFunction> funcs = new HashMap<>();
@Nullable List<KernelFunction<?>> functions) {
Map<String, KernelFunction<?>> funcs = new HashMap<>();
if (functions != null) {
funcs = functions.stream().collect(Collectors.toMap(KernelFunction::getName, f -> f));
funcs = functions.stream().collect(Collectors.toMap(KernelFunction<?>::getName, f -> f));
}
return new KernelPlugin(pluginName, description, funcs);
}
@@ -163,7 +172,7 @@ public class KernelPluginFactory {
throw new SKException("No Plugins found in directory " + pluginDir.getAbsolutePath());
}
Map<String, KernelFunction> plugins = new CaseInsensitiveMap<>();
Map<String, KernelFunction<?>> plugins = new CaseInsensitiveMap<>();
for (File dir : files) {
try {
@@ -180,7 +189,7 @@ public class KernelPluginFactory {
// configuration, unable to parse {configPath}");
}
KernelFunction plugin = getKernelFunction(promptTemplateFactory, configPath,
KernelFunction<?> plugin = getKernelFunction(promptTemplateFactory, configPath,
promptPath);
plugins.put(dir.getName(), plugin);
@@ -196,7 +205,7 @@ public class KernelPluginFactory {
);
}
private static KernelFunction getKernelFunction(
private static KernelFunction<?> getKernelFunction(
PromptTemplateFactory promptTemplateFactory,
File configPath,
File promptPath)
@@ -217,7 +226,8 @@ public class KernelPluginFactory {
}
}
private static KernelFunction getKernelFunction(
@SuppressWarnings("unchecked")
private static <T> KernelFunction<T> getKernelFunction(
PromptTemplateFactory promptTemplateFactory,
PromptTemplateConfig config,
String template) {
@@ -229,7 +239,7 @@ public class KernelPluginFactory {
promptTemplate = new KernelPromptTemplateFactory().tryCreate(config);
}
return new KernelFunctionFromPrompt.Builder()
return (KernelFunction<T>) new KernelFunctionFromPrompt.Builder<>()
.withName(config.getName())
.withDescription(config.getDescription())
.withExecutionSettings(config.getExecutionSettings())
@@ -261,10 +271,10 @@ public class KernelPluginFactory {
+ pluginDirectoryName);
return null;
}
KernelFunction function = getKernelFunction(promptTemplateFactory,
KernelFunction<?> function = getKernelFunction(promptTemplateFactory,
promptTemplateConfig, template);
HashMap<String, KernelFunction> plugins = new HashMap<>();
HashMap<String, KernelFunction<?>> plugins = new HashMap<>();
plugins.put(functionName, function);
@@ -7,21 +7,12 @@ import javax.annotation.Nullable;
public class InputVariable {
@JsonProperty("name")
private String name;
@JsonProperty("type")
private String type;
@Nullable
@JsonProperty("description")
private String description;
@JsonProperty("default")
@Nullable
private String defaultValue;
@JsonProperty("is_required")
private boolean isRequired;
public InputVariable(String name) {
@@ -44,7 +35,7 @@ public class InputVariable {
@JsonProperty("default")
@Nullable
String defaultValue,
@JsonProperty("isRequired")
@JsonProperty("is_required")
boolean isRequired) {
this.name = name;
@@ -1,28 +1,5 @@
package com.microsoft.semantickernel.semanticfunctions;
import static com.microsoft.semantickernel.plugin.annotations.KernelFunctionParameter.NO_DEFAULT_VALUE;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.exceptions.AIException;
import com.microsoft.semantickernel.exceptions.AIException.ErrorCodes;
import com.microsoft.semantickernel.hooks.FunctionInvokedEvent;
import com.microsoft.semantickernel.hooks.FunctionInvokingEvent;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.orchestration.DefaultKernelFunction;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionMetadata;
import com.microsoft.semantickernel.orchestration.MethodDetails;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter.NoopConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelParameterMetadata;
import com.microsoft.semantickernel.plugin.KernelReturnParameterMetadata;
import com.microsoft.semantickernel.plugin.annotations.DefineKernelFunction;
import com.microsoft.semantickernel.plugin.annotations.KernelFunctionParameter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
@@ -32,20 +9,47 @@ import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.exceptions.AIException;
import com.microsoft.semantickernel.exceptions.SKException;
import com.microsoft.semantickernel.exceptions.AIException.ErrorCodes;
import com.microsoft.semantickernel.hooks.FunctionInvokedEvent;
import com.microsoft.semantickernel.hooks.FunctionInvokingEvent;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.InvocationContext;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionMetadata;
import com.microsoft.semantickernel.orchestration.MethodDetails;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypeConverter.NoopConverter;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.plugin.KernelParameterMetadata;
import com.microsoft.semantickernel.plugin.KernelReturnParameterMetadata;
import com.microsoft.semantickernel.plugin.annotations.DefineKernelFunction;
import com.microsoft.semantickernel.plugin.annotations.KernelFunctionParameter;
import static com.microsoft.semantickernel.plugin.annotations.KernelFunctionParameter.NO_DEFAULT_VALUE;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
public class KernelFunctionFromMethod extends DefaultKernelFunction {
public class KernelFunctionFromMethod<T> extends KernelFunction<T> {
private final static Logger LOGGER = LoggerFactory.getLogger(KernelFunctionFromMethod.class);
private final ImplementationFunc function;
private final ImplementationFunc<T> function;
private KernelFunctionFromMethod(
ImplementationFunc implementationFunc,
ImplementationFunc<T> implementationFunc,
String functionName,
@Nullable
String description,
@@ -64,72 +68,37 @@ public class KernelFunctionFromMethod extends DefaultKernelFunction {
this.function = implementationFunc;
}
/**
* Concrete implementation of the abstract method in KernelFunction.
* {@inheritDoc}
*/
@Override
public <T> Mono<FunctionResult<T>> invokeAsync(
public Mono<FunctionResult<T>> invokeAsync(
Kernel kernel,
@Nullable KernelArguments arguments,
@Nullable ContextVariableType<T> variableType) {
return invokeAsync(
kernel,
arguments,
kernel.getHookService(),
variableType);
}
@Override
public <T> Mono<FunctionResult<T>> invokeAsync(
Kernel kernel,
@Nullable KernelArguments arguments,
@Nullable KernelHooks kernelHooks,
@Nullable ContextVariableType<T> variableType) {
if (kernelHooks == null) {
kernelHooks = kernel.getHookService();
}
return function
.invoke(kernel, this, arguments, kernelHooks)
.map(it -> convertVariableToReturnType(variableType, it));
}
private <T> FunctionResult convertVariableToReturnType(
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> variableType,
FunctionResult<Object> it) {
if (variableType != null) {
return new FunctionResult<>(
variableType.of(it.getResult()),
it.getMetadata());
} else {
Object result = it.getResult();
if (result != null && getMetadata().getReturnParameter().getParameterType()
.isAssignableFrom(result.getClass())) {
return new FunctionResult<>(
new ContextVariable<>(
new ContextVariableType<>(
new NoopConverter(
getMetadata().getReturnParameter().getParameterType()),
getMetadata().getReturnParameter().getParameterType()
),
it.getResult())
);
}
throw new RuntimeException("Unable to convert result to type: "
+ getMetadata().getReturnParameter().getParameterType().getName());
}
@Nullable InvocationContext invocationContext) {
return function.invoke(kernel, this, arguments, variableType, invocationContext);
}
public interface ImplementationFunc {
@Override
public Mono<FunctionResult<T>> invokeAsync(Kernel kernel, KernelFunctionArguments arguments, ContextVariableType<T> variableType) {
return super.invokeAsync(kernel, arguments, variableType);
}
<T> Mono<FunctionResult<T>> invoke(
public interface ImplementationFunc<T> {
Mono<FunctionResult<T>> invoke(
Kernel kernel,
KernelFunction function,
@Nullable
KernelArguments arguments,
KernelHooks kernelHooks);
KernelFunction<T> function,
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> variableType,
@Nullable InvocationContext invocationContext);
}
public static KernelFunction create(
@SuppressWarnings("unchecked")
public static <T> KernelFunction<T> create(
Method method,
Object target,
@Nullable
@@ -138,7 +107,6 @@ public class KernelFunctionFromMethod extends DefaultKernelFunction {
String description,
@Nullable
List<KernelParameterMetadata<?>> parameters,
@Nullable
KernelReturnParameterMetadata<?> returnParameter) {
MethodDetails methodDetails = getMethodDetails(functionName, method, target);
@@ -155,7 +123,8 @@ public class KernelFunctionFromMethod extends DefaultKernelFunction {
returnParameter = methodDetails.getReturnParameter();
}
return new KernelFunctionFromMethod(
// unchecked cast
return (KernelFunction<T>) new KernelFunctionFromMethod<>(
methodDetails.getFunction(),
methodDetails.getName(),
description,
@@ -196,21 +165,24 @@ public class KernelFunctionFromMethod extends DefaultKernelFunction {
}
private static ImplementationFunc getFunction(Method method, Object instance) {
@SuppressWarnings("unchecked")
private static <T> ImplementationFunc<T> getFunction(Method method, Object instance) {
return new ImplementationFunc() {
@Override
public <T> Mono<FunctionResult<T>> invoke(
Kernel kernel,
KernelFunction function,
@Nullable
KernelArguments arguments,
KernelHooks kernelHooks) {
return (kernel, function, arguments, variableType, invocationContext) -> {
if (invocationContext == null) {
invocationContext = InvocationContext.builder().build();
}
FunctionInvokingEvent updatedState = kernelHooks
.executeHooks(
new FunctionInvokingEvent(function, arguments));
KernelArguments updatedArguments = updatedState.getArguments();
// kernelHooks must be effectively final for lambda
KernelHooks kernelHooks = invocationContext.getKernelHooks() != null
? invocationContext.getKernelHooks()
: kernel.getGlobalKernelHooks();
assert kernelHooks != null : "getGlobalKernelHooks() should never return null!";
FunctionInvokingEvent updatedState = kernelHooks
.executeHooks(
new FunctionInvokingEvent(function, arguments));
KernelFunctionArguments updatedArguments = updatedState != null ? updatedState.getArguments() : arguments;
try {
List<Object> args =
@@ -220,7 +192,7 @@ public class KernelFunctionFromMethod extends DefaultKernelFunction {
Mono<?> mono;
if (method.getReturnType().isAssignableFrom(Mono.class)) {
mono = (Mono) method.invoke(instance, args.toArray());
mono = (Mono<?>) method.invoke(instance, args.toArray());
} else {
mono = invokeAsyncFunction(method, instance, args);
}
@@ -238,21 +210,32 @@ public class KernelFunctionFromMethod extends DefaultKernelFunction {
return r
.map(it -> {
return new FunctionResult(
new ContextVariable(
new ContextVariableType(
new NoopConverter(
function
.getMetadata()
.getReturnParameter()
.getParameterType()
),
function
.getMetadata()
.getReturnParameter()
.getParameterType()
),
it));
// If given a variable type, use it.
// If it's wrong, then it's a programming error on the part of the caller.
if (variableType != null) {
return new FunctionResult<>(new ContextVariable<>(variableType, it));
}
Class<?> returnParameterType = function
.getMetadata()
.getReturnParameter()
.getParameterType();
// If the function has a return type that has a ContextVariableType<T>, use it.
ContextVariableType<T> contextVariableType = getContextVariableType(returnParameterType);
if (contextVariableType == null) {
// If getting the context variable type from the function fails, default to
// using the NoopConverter.
contextVariableType = getDefaultContextVariableType(returnParameterType);
}
if (contextVariableType != null) {
return new FunctionResult<>(new ContextVariable<>(contextVariableType, it));
}
// If we get here, then either the returnParameterType doesn't match T
throw new SKException(String.format("Return parameter type from %s.%s does not match the expected type %s", function.getSkillName(), function.getName(), it.getClass().getName()));
})
.map(it -> {
FunctionInvokedEvent<T> updatedResult = kernelHooks
@@ -266,8 +249,45 @@ public class KernelFunctionFromMethod extends DefaultKernelFunction {
} catch (Exception e) {
return Mono.error(e);
}
};
}
@Nullable
@SuppressWarnings("unchecked")
private static <T> ContextVariableType<T> getContextVariableType(Class<?> clazz) {
if (clazz != null) {
try {
// unchecked cast
Class<T> tClazz = (Class<T>) clazz;
ContextVariableType<T> type = ContextVariableTypes.getDefaultVariableTypeForClass(tClazz);
return type;
} catch (ClassCastException | SKException e) {
// SKException is thrown from ContextVariableTypes.getDefaultVariableTypeForClass
// if there is no default variable type for the class.
// Fallthrough. Let the caller handle a null return.
}
};
}
return null;
}
@Nullable
@SuppressWarnings("unchecked")
private static <T> ContextVariableType<T> getDefaultContextVariableType(Class<?> clazz) {
if (clazz != null) {
try {
// unchecked cast
Class<T> tClazz = (Class<T>) clazz;
ContextVariableTypeConverter<T> noopConverter = new NoopConverter<>(tClazz);
return new ContextVariableType<>(noopConverter, tClazz);
} catch (ClassCastException e) {
// Fallthrough. Let the caller handle a null return.
}
}
return null;
}
private static Mono<Object> invokeAsyncFunction(
@@ -306,10 +326,10 @@ public class KernelFunctionFromMethod extends DefaultKernelFunction {
private static Function<Parameter, Object> getParameters(
Method method,
@Nullable
KernelArguments context,
KernelFunctionArguments context,
Kernel kernel) {
return parameter -> {
if (KernelArguments.class.isAssignableFrom(parameter.getType())) {
if (KernelFunctionArguments.class.isAssignableFrom(parameter.getType())) {
return context;
} else {
return getArgumentValue(method, context, parameter, kernel);
@@ -320,7 +340,7 @@ public class KernelFunctionFromMethod extends DefaultKernelFunction {
@Nullable
private static Object getArgumentValue(
Method method,
@Nullable KernelArguments context,
@Nullable KernelFunctionArguments context,
Parameter parameter,
Kernel kernel) {
String variableName = getGetVariableName(parameter);
@@ -1,6 +1,19 @@
package com.microsoft.semantickernel.semanticfunctions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.azure.core.exception.HttpResponseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.semantickernel.AIService;
@@ -14,30 +27,23 @@ import com.microsoft.semantickernel.hooks.FunctionInvokingEvent;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.hooks.PromptRenderedEvent;
import com.microsoft.semantickernel.hooks.PromptRenderingEvent;
import com.microsoft.semantickernel.orchestration.DefaultKernelFunction;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.InvocationContext;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionMetadata;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.orchestration.contextvariables.DefaultKernelArguments;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelParameterMetadata;
import com.microsoft.semantickernel.services.AIServiceSelection;
import com.microsoft.semantickernel.textcompletion.TextGenerationService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public class KernelFunctionFromPrompt extends DefaultKernelFunction {
public class KernelFunctionFromPrompt<T> extends KernelFunction<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(KernelFunctionFromPrompt.class);
@@ -68,7 +74,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
}
}
public static KernelFunction create(
public static <T> KernelFunction<T> create(
PromptTemplateConfig promptConfig
) {
return create(
@@ -77,7 +83,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
);
}
public static KernelFunction create(
public static <T> KernelFunction<T> create(
PromptTemplateConfig promptConfig,
@Nullable
PromptTemplateFactory promptTemplateFactory
@@ -90,32 +96,40 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
}
public static KernelFunction create(
public static <T> KernelFunction<T> create(
PromptTemplate promptTemplate,
PromptTemplateConfig promptConfig) {
return new KernelFunctionFromPrompt(
return new KernelFunctionFromPrompt<>(
promptTemplate,
promptConfig,
null
);
}
private <T> Flux<FunctionResult<T>> invokeInternalAsync(
private Flux<FunctionResult<T>> invokeInternalAsync(
Kernel kernel,
@Nullable KernelArguments argumentsIn,
KernelHooks kernelHooks,
ContextVariableType<T> variableType) {
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> contextVariableType,
@Nullable InvocationContext invocationContext) {
KernelArguments arguments;
if (argumentsIn == null) {
arguments = new DefaultKernelArguments();
} else {
arguments = argumentsIn;
}
InvocationContext context = invocationContext != null ? invocationContext : InvocationContext.builder().build();
// must be effectively final for lambda
KernelHooks kernelHooks = context.getKernelHooks() != null
? context.getKernelHooks()
: kernel.getGlobalKernelHooks();
assert kernelHooks != null : "getGlobalKernelHooks() should never return null";
PromptRenderingEvent preRenderingHookResult = kernelHooks
.executeHooks(new PromptRenderingEvent(this, arguments));
// TOOD: put in method, add catch for classcastexception, fallback to noopconverter
ContextVariableType<T> variableType = contextVariableType != null
? contextVariableType
: ContextVariableTypes.<T>getDefaultVariableTypeForClass(
(Class<T>) this.getMetadata().getReturnParameter().getParameterType()
);
return this
.template
.renderAsync(kernel, preRenderingHookResult.getArguments())
@@ -123,7 +137,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
PromptRenderedEvent promptHookResult = kernelHooks
.executeHooks(new PromptRenderedEvent(this, arguments, prompt));
prompt = promptHookResult.getPrompt();
KernelArguments args = promptHookResult.getArguments();
KernelFunctionArguments args = promptHookResult.getArguments();
LOGGER.info("RENDERED PROMPT: \n{}", prompt);
@@ -131,7 +145,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
.executeHooks(new FunctionInvokingEvent(this, args));
args = updateArguments.getArguments();
AIServiceSelection aiServiceSelection = kernel
AIServiceSelection<?> aiServiceSelection = kernel
.getServiceSelector()
.trySelectAIService(
TextAIService.class,
@@ -139,28 +153,23 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
args
);
AIService client = aiServiceSelection != null ? aiServiceSelection.getService() : null;
if (aiServiceSelection == null) {
throw new IllegalStateException(
"Failed to initialise aiService, could not find any TextAIService implementations");
}
AIService client = aiServiceSelection.getService();
if (client == null) {
throw new IllegalStateException(
"Failed to initialise aiService, could not find any TextAIService implementations");
}
Flux<FunctionResult<T>> result;
// settings from prompt or use default
PromptExecutionSettings executionSettings = aiServiceSelection.getSettings();
if (client instanceof ChatCompletionService) {
result = ((ChatCompletionService) client)
.getChatMessageContentsAsync(
prompt,
executionSettings,
kernel,
kernelHooks)
context)
.flatMapMany(Flux::fromIterable)
.concatMap(chatMessageContent -> {
if (chatMessageContent.getAuthorRole()
@@ -190,8 +199,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
return Flux.error(new IllegalStateException(
"Tool message content is empty"));
}
Mono<FunctionResult<String>> toolResult = invokeTool(kernel,
content);
Mono<FunctionResult<T>> toolResult = invokeTool(kernel,content);
return toolResult.flux();
}
return Flux.empty();
@@ -282,36 +290,16 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
}
@Override
public <T> Mono<FunctionResult<T>> invokeAsync(
public Mono<FunctionResult<T>> invokeAsync(
Kernel kernel,
@Nullable KernelArguments arguments,
@Nullable KernelHooks kernelHooks,
@Nullable
ContextVariableType<T> variableType) {
if (variableType == null) {
return Mono.error(new SKException(
"Cannot invoke a prompt function without a variable return type. Ensure that there is"
+ " a valid type converter for the return type of the prompt function."));
}
if (kernelHooks == null) {
kernelHooks = kernel.getHookService();
}
return invokeInternalAsync(kernel, arguments, kernelHooks, variableType)
.take(1)
.single();
}
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> variableType,
@Nullable InvocationContext invocationContext) {
@Override
public <T> Mono<FunctionResult<T>> invokeAsync(
Kernel kernel,
@Nullable
KernelArguments arguments,
@Nullable
ContextVariableType<T> variableType) {
return invokeAsync(kernel, arguments, null, variableType);
return invokeInternalAsync(kernel, arguments, variableType, invocationContext)
.take(1).single();
}
/*
* Given a json string, invoke the tool specified in the json string.
* At this time, the only tool we have is 'function'.
@@ -319,7 +307,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
* {"type":"function", "function": {"name":"search-search", "parameters": {"query":"Banksy"}}}
* where 'name' is <plugin name '-' function name>.
*/
private Mono<FunctionResult<String>> invokeTool(Kernel kernel, String json) {
private Mono<FunctionResult<T>> invokeTool(Kernel kernel, String json) {
try {
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(json);
@@ -327,8 +315,10 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
if (jsonNode != null) {
return invokeFunction(kernel, jsonNode);
}
} catch (Exception e) {
} catch (JsonProcessingException e) {
LOGGER.error("Failed to parse json", e);
} catch (Exception e) {
LOGGER.error("Failed to invoke tool", e);
}
return Mono.empty();
}
@@ -336,8 +326,8 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
/*
* The jsonNode should represent: {"name":"search-search", "parameters": {"query":"Banksy"}}}
*/
@SuppressWarnings("StringSplitter")
private Mono<FunctionResult<String>> invokeFunction(Kernel kernel, JsonNode jsonNode) {
@SuppressWarnings({"StringSplitter", "unchecked"})
private Mono<FunctionResult<T>> invokeFunction(Kernel kernel, JsonNode jsonNode) {
String name = jsonNode.get("name").asText();
String[] parts = name.split("-");
String pluginName = parts.length > 0 ? parts[0] : "";
@@ -345,21 +335,38 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
JsonNode parameters = jsonNode.get("parameters");
if (parameters != null) {
try {
KernelFunction kernelFunction = kernel.getPlugins().getFunction(pluginName, fnName);
KernelFunction<T> kernelFunction = null;
try {
// unchecked cast
kernelFunction = (KernelFunction<T>)kernel.getPlugins().getFunction(pluginName, fnName);
} catch (IllegalArgumentException | ClassCastException e) {
return Mono.error(new SKException(e.getMessage(), e));
}
List<KernelParameterMetadata<?>> params = kernelFunction.getMetadata().getParameters();
Map<String, KernelParameterMetadata<?>> parameterMetaaData =
params.stream()
.collect(Collectors.toMap(KernelParameterMetadata::getName, it -> it));
ContextVariableType<String> variableType = ContextVariableTypes.getDefaultVariableTypeForClass(
String.class);
Map<String, ContextVariable<?>> variables = new HashMap<>();
parameters.fields().forEachRemaining(entry -> {
String paramName = entry.getKey();
String paramValue = entry.getValue().asText();
ContextVariable<String> contextVariable = new ContextVariable<>(variableType,
paramValue);
KernelParameterMetadata<?> parameterMetadata = parameterMetaaData.get(paramName);
if (parameterMetadata == null) {
// parameter in json not found in function metadata
// TODO: this shouldn't happen, so log it.
return;
}
Class<?> parameterType = parameterMetadata.getType();
ContextVariable<?> contextVariable = ContextVariable.untypedOf(paramValue, parameterType);
variables.put(paramName, contextVariable);
});
KernelArguments arguments = KernelArguments.builder().withVariables(variables)
KernelFunctionArguments arguments = KernelFunctionArguments.builder().withVariables(variables)
.build();
return kernelFunction.invokeAsync(kernel, arguments, variableType);
return kernelFunction.invokeAsync(kernel, arguments);
} catch (Exception e) {
return Mono.error(e);
}
@@ -367,7 +374,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
return Mono.empty();
}
public static KernelFunction create(
public static <T> KernelFunction<T> create(
String promptTemplate) {
return create(promptTemplate, null, null, null, null, null);
}
@@ -383,7 +390,8 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
/// <param name="promptTemplateFactory">Optional: Prompt template factory</param>
/// <param name="loggerFactory">Logger factory</param>
/// <returns>A function ready to use</returns>
public static KernelFunction create(
@SuppressWarnings("unchecked")
public static <T> KernelFunction<T> create(
String promptTemplate,
@Nullable Map<String, PromptExecutionSettings> executionSettings,
@Nullable String functionName,
@@ -399,7 +407,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
functionName = UUID.randomUUID().toString();
}
return new KernelFunctionFromPrompt.Builder()
return (KernelFunction<T>) new KernelFunctionFromPrompt.Builder<>()
.withName(functionName)
.withDescription(description)
.withPromptTemplateFactory(promptTemplateFactory)
@@ -409,11 +417,11 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
.build();
}
public static Builder builder() {
return new Builder();
public static <T> Builder<T> builder() {
return new Builder<>();
}
public static final class Builder implements FromPromptBuilder {
public static final class Builder<T> implements FromPromptBuilder<T> {
@Nullable
private PromptTemplate promptTemplate;
@@ -435,13 +443,13 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
@Override
public FromPromptBuilder withName(@Nullable String name) {
public FromPromptBuilder<T> withName(@Nullable String name) {
this.name = name;
return this;
}
@Override
public FromPromptBuilder withInputParameters(@Nullable List<InputVariable> inputVariables) {
public FromPromptBuilder<T> withInputParameters(@Nullable List<InputVariable> inputVariables) {
if (inputVariables != null) {
this.inputVariables = new ArrayList<>(inputVariables);
} else {
@@ -451,13 +459,13 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
}
@Override
public FromPromptBuilder withPromptTemplate(@Nullable PromptTemplate promptTemplate) {
public FromPromptBuilder<T> withPromptTemplate(@Nullable PromptTemplate promptTemplate) {
this.promptTemplate = promptTemplate;
return this;
}
@Override
public FromPromptBuilder withExecutionSettings(
public FromPromptBuilder<T> withExecutionSettings(
@Nullable
Map<String, PromptExecutionSettings> executionSettings) {
if (this.executionSettings == null) {
@@ -471,7 +479,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
}
@Override
public FromPromptBuilder withDefaultExecutionSettings(
public FromPromptBuilder<T> withDefaultExecutionSettings(
@Nullable PromptExecutionSettings executionSettings) {
if (executionSettings == null) {
return this;
@@ -491,32 +499,37 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
}
@Override
public FromPromptBuilder withDescription(@Nullable String description) {
public FromPromptBuilder<T> withDescription(@Nullable String description) {
this.description = description;
return this;
}
@Override
public FromPromptBuilder withTemplate(@Nullable String template) {
public FromPromptBuilder<T> withTemplate(@Nullable String template) {
this.template = template;
return this;
}
@Override
public FromPromptBuilder withTemplateFormat(String templateFormat) {
public FromPromptBuilder<T> withTemplateFormat(String templateFormat) {
this.templateFormat = templateFormat;
return this;
}
@Override
public FromPromptBuilder withOutputVariable(@Nullable OutputVariable outputVariable) {
public FromPromptBuilder<T> withOutputVariable(@Nullable OutputVariable outputVariable) {
this.outputVariable = outputVariable;
return this;
}
@Override
public FromPromptBuilder withPromptTemplateFactory(
public FromPromptBuilder<T> withOutputVariable(@Nullable String description, String type) {
return this.withOutputVariable(new OutputVariable(description, type));
}
@Override
public FromPromptBuilder<T> withPromptTemplateFactory(
@Nullable
PromptTemplateFactory promptTemplateFactory) {
this.promptTemplateFactory = promptTemplateFactory;
@@ -524,7 +537,7 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
}
@Override
public KernelFunction build() {
public KernelFunction<T> build() {
if (template == null) {
throw new IllegalStateException("Template must be provided");
@@ -549,17 +562,17 @@ public class KernelFunctionFromPrompt extends DefaultKernelFunction {
temp = new KernelPromptTemplateFactory().tryCreate(config);
}
return new KernelFunctionFromPrompt(temp, config, executionSettings);
return new KernelFunctionFromPrompt<>(temp, config, executionSettings);
}
public KernelFunction build(PromptTemplateConfig functionModel) {
public KernelFunction<T> build(PromptTemplateConfig functionModel) {
if (promptTemplate == null) {
throw new IllegalStateException("Template must be provided");
}
return new KernelFunctionFromPrompt(
return new KernelFunctionFromPrompt<>(
promptTemplate,
functionModel,
executionSettings
@@ -4,7 +4,8 @@ package com.microsoft.semantickernel.semanticfunctions;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import javax.annotation.Nullable;
import reactor.core.publisher.Mono;
@@ -21,6 +22,6 @@ public interface PromptTemplate extends Buildable {
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>Prompt rendered to string</returns>
Mono<String> renderAsync(Kernel kernel,
@Nullable KernelArguments arguments);
@Nullable KernelFunctionArguments arguments);
}
@@ -7,6 +7,7 @@ import javax.annotation.Nullable;
/**
* The result of an AI service selection.
* @param <T> The type of AI service.
*/
public class AIServiceSelection<T extends AIService> {
@@ -3,7 +3,8 @@ package com.microsoft.semantickernel.services;
import com.microsoft.semantickernel.AIService;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import javax.annotation.Nullable;
/**
@@ -17,7 +18,7 @@ public interface AIServiceSelector {
* Resolves an {@link AIService} and associated and
* {@link com.microsoft.semantickernel.orchestration.PromptExecutionSettings} from the specified
* {@link com.microsoft.semantickernel.Kernel} based on the associated {@link KernelFunction}
* and {@link KernelArguments}.
* and {@link KernelFunctionArguments}.
*
* @param serviceType The type of service to select. This must be the same type with which the
* service was registered in the {@link AIServiceSelection}
@@ -29,9 +30,9 @@ public interface AIServiceSelector {
<T extends AIService> AIServiceSelection<T> trySelectAIService(
Class<T> serviceType,
@Nullable
KernelFunction function,
KernelFunction<?> function,
@Nullable
KernelArguments arguments
KernelFunctionArguments arguments
);
}
@@ -2,7 +2,8 @@ package com.microsoft.semantickernel.services;
import com.microsoft.semantickernel.AIService;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import java.util.Map;
import javax.annotation.Nullable;
import org.slf4j.Logger;
@@ -23,10 +24,10 @@ public abstract class BaseAIServiceSelector implements AIServiceSelector {
public <T extends AIService> AIServiceSelection<T> trySelectAIService(
Class<T> serviceType,
@Nullable
KernelFunction function,
KernelFunction<?> function,
@Nullable
KernelArguments arguments
KernelFunctionArguments arguments
) {
return trySelectAIService(serviceType, function, arguments, services);
}
@@ -36,9 +37,9 @@ public abstract class BaseAIServiceSelector implements AIServiceSelector {
Class<T> serviceType,
@Nullable
KernelFunction function,
KernelFunction<?> function,
@Nullable
KernelArguments arguments,
KernelFunctionArguments arguments,
Map<Class<? extends AIService>, AIService> services);
}
@@ -1,21 +1,24 @@
package com.microsoft.semantickernel.services;
import com.microsoft.semantickernel.AIService;
import com.microsoft.semantickernel.Verify;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.textcompletion.TextGenerationService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.microsoft.semantickernel.AIService;
import com.microsoft.semantickernel.Verify;
import com.microsoft.semantickernel.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.textcompletion.TextGenerationService;
public class OrderedAIServiceSelector extends BaseAIServiceSelector {
private static final Logger LOGGER = LoggerFactory.getLogger(OrderedAIServiceSelector.class);
@@ -32,23 +35,25 @@ public class OrderedAIServiceSelector extends BaseAIServiceSelector {
@Override
public <T extends AIService> AIServiceSelection<T> trySelectAIService(
Class<T> serviceType,
@Nullable
KernelFunction function,
KernelFunction<?> function,
@Nullable
KernelArguments arguments,
KernelFunctionArguments arguments,
Map<Class<? extends AIService>, AIService> services) {
// Allow the execution settings from the kernel arguments to take precedence
Map<String, PromptExecutionSettings> executionSettings = settingsFromArguments(arguments);
executionSettings = settingsFromFunctionSettings(function, executionSettings);
Map<String, PromptExecutionSettings> executionSettings =
settingsFromFunctionSettings(function);
if (executionSettings == null || executionSettings.isEmpty()) {
AIService service = getAnyService(serviceType);
if (service != null) {
return new AIServiceSelection(service, null);
return castServiceSelection(new AIServiceSelection<>(service, null));
}
} else {
AIServiceSelection selection = executionSettings
AIServiceSelection<?> selection = executionSettings
.entrySet()
.stream()
.map(keyValue -> {
@@ -59,7 +64,7 @@ public class OrderedAIServiceSelector extends BaseAIServiceSelector {
if (!Verify.isNullOrEmpty(serviceId)) {
AIService service = getService(serviceId);
if (service != null) {
return new AIServiceSelection(service, settings);
return castServiceSelection(new AIServiceSelection<>(service, settings));
}
}
@@ -70,7 +75,7 @@ public class OrderedAIServiceSelector extends BaseAIServiceSelector {
.orElseGet(() -> null);
if (selection != null) {
return selection;
return castServiceSelection(selection);
}
selection = executionSettings
@@ -82,7 +87,7 @@ public class OrderedAIServiceSelector extends BaseAIServiceSelector {
if (!Verify.isNullOrEmpty(settings.getModelId())) {
AIService service = getServiceByModelId(settings.getModelId());
if (service != null) {
return new AIServiceSelection(service, settings);
return castServiceSelection(new AIServiceSelection<>(service, settings));
}
}
@@ -93,14 +98,14 @@ public class OrderedAIServiceSelector extends BaseAIServiceSelector {
.orElseGet(() -> null);
if (selection != null) {
return selection;
return castServiceSelection(selection);
}
}
AIService defaultService = getService(PromptExecutionSettings.DEFAULT_SERVICE_ID);
if (defaultService != null && serviceType.isAssignableFrom(defaultService.getClass())) {
return new AIServiceSelection(defaultService, null);
return castServiceSelection(new AIServiceSelection<>(defaultService, null));
}
AIService service = getAnyService(serviceType);
@@ -115,33 +120,30 @@ public class OrderedAIServiceSelector extends BaseAIServiceSelector {
}
if (service != null) {
return new AIServiceSelection(service, settings);
return castServiceSelection(new AIServiceSelection<>(service, settings));
}
LOGGER.warn("No service found meeting requirements");
return null;
}
@Nullable
private static Map<String, PromptExecutionSettings> settingsFromFunctionSettings(
@Nullable
KernelFunction function,
@Nullable
Map<String, PromptExecutionSettings> executionSettings) {
if (executionSettings == null || executionSettings.isEmpty()) {
if (function != null) {
executionSettings = function.getExecutionSettings();
}
@SuppressWarnings("unchecked")
private static <T extends AIService> AIServiceSelection<T> castServiceSelection(AIServiceSelection<?> selection) {
try {
// unchecked cast
return (AIServiceSelection<T>) selection;
} catch (ClassCastException e) {
LOGGER.debug("%s", e.getMessage());
return null;
}
return executionSettings;
}
@Nullable
private static Map<String, PromptExecutionSettings> settingsFromArguments(
private static Map<String, PromptExecutionSettings> settingsFromFunctionSettings(
@Nullable
KernelArguments arguments) {
if (arguments != null) {
return arguments.getExecutionSettings();
KernelFunction function) {
if (function != null) {
return function.getExecutionSettings();
}
return null;
}
@@ -1,23 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.templateengine.handlebars;
import com.github.jknack.handlebars.Context;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Options;
import com.github.jknack.handlebars.ValueResolver;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.chatcompletion.ChatMessageContent;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.DefaultKernelArguments;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.plugin.KernelParameterMetadata;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginCollection;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -28,8 +11,27 @@ import java.util.Locale;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.github.jknack.handlebars.Context;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Options;
import com.github.jknack.handlebars.ValueResolver;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.chatcompletion.ChatMessageContent;
import com.microsoft.semantickernel.orchestration.KernelFunction;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.plugin.KernelParameterMetadata;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.plugin.KernelPluginCollection;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import reactor.core.publisher.Mono;
public class HandlebarsPromptTemplate implements PromptTemplate {
@@ -45,12 +47,12 @@ public class HandlebarsPromptTemplate implements PromptTemplate {
@Override
public Mono<String> renderAsync(
Kernel kernel,
@Nullable KernelArguments arguments) {
@Nullable KernelFunctionArguments arguments) {
HandleBarsPromptTemplateHandler handler =
new HandleBarsPromptTemplateHandler(kernel, promptTemplate.getTemplate());
if (arguments == null) {
arguments = new DefaultKernelArguments();
arguments = new KernelFunctionArguments();
}
return handler.render(arguments);
}
@@ -128,8 +130,8 @@ public class HandlebarsPromptTemplate implements PromptTemplate {
@Override
public Object resolve(Object context, String name) {
Object value = null;
if (context instanceof KernelArguments) {
ContextVariable<?> variable = ((KernelArguments) context).get(name);
if (context instanceof KernelFunctionArguments) {
ContextVariable<?> variable = ((KernelFunctionArguments) context).get(name);
value = variable != null ? variable.getValue() : null;
}
if (context instanceof ContextVariable) {
@@ -153,9 +155,9 @@ public class HandlebarsPromptTemplate implements PromptTemplate {
@Override
public Set<Entry<String, Object>> propertySet(Object context) {
if (context instanceof KernelArguments) {
if (context instanceof KernelFunctionArguments) {
HashMap<String, Object> result = new HashMap<>();
result.putAll((KernelArguments) context);
result.putAll((KernelFunctionArguments) context);
return result.entrySet();
} else if (context instanceof ContextVariable) {
HashMap<String, Object> result = new HashMap<>();
@@ -232,9 +234,9 @@ public class HandlebarsPromptTemplate implements PromptTemplate {
Iterator<KernelPlugin> plugins = ((KernelPluginCollection) context).iterator();
while (plugins.hasNext()) {
KernelPlugin plugin = plugins.next();
Iterator<KernelFunction> functions = plugin.iterator();
Iterator<KernelFunction<?>> functions = plugin.iterator();
while (functions.hasNext()) {
KernelFunction function = functions.next();
KernelFunction<?> function = functions.next();
sb.append(options.fn(function));
}
}
@@ -268,7 +270,7 @@ public class HandlebarsPromptTemplate implements PromptTemplate {
}
public Mono<String> render(KernelArguments variables) {
public Mono<String> render(KernelFunctionArguments variables) {
try {
ArrayList<ValueResolver> resolvers = new ArrayList<>();
resolvers.add(new MessageResolver());
@@ -3,7 +3,7 @@ package com.microsoft.semantickernel.templateengine.semantickernel;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.Verify;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.semanticfunctions.InputVariable;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
@@ -96,7 +96,7 @@ public class DefaultPromptTemplate implements PromptTemplate {
@Override
public Mono<String> renderAsync(
Kernel kernel,
@Nullable KernelArguments arguments) {
@Nullable KernelFunctionArguments arguments) {
List<Block> blocks = this.extractBlocks();
addMissingInputVariables(blocks);
@@ -1,24 +1,25 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.templateengine.semantickernel.blocks;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.exceptions.SKException;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionMetadata;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.orchestration.contextvariables.DefaultKernelArguments;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException;
import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException.ErrorCodes;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
public final class CodeBlock extends Block implements CodeRendering {
@@ -78,7 +79,7 @@ public final class CodeBlock extends Block implements CodeRendering {
}
@Override
public Mono<String> renderCodeAsync(Kernel kernel, @Nullable KernelArguments arguments) {
public Mono<String> renderCodeAsync(Kernel kernel, @Nullable KernelFunctionArguments arguments) {
if (!this.isValid()) {
throw new TemplateException(ErrorCodes.SYNTAX_ERROR);
}
@@ -113,7 +114,7 @@ public final class CodeBlock extends Block implements CodeRendering {
private <T> Mono<ContextVariable<T>> renderFunctionCallAsync(
FunctionIdBlock fBlock,
Kernel kernel,
@Nullable KernelArguments arguments,
@Nullable KernelFunctionArguments arguments,
ContextVariableType<T> resultType) {
// If the code syntax is {{functionName $varName}} use $varName instead of $input
@@ -121,11 +122,9 @@ public final class CodeBlock extends Block implements CodeRendering {
if (this.tokens.size() > 1) {
//Cloning the original arguments to avoid side effects - arguments added to the original arguments collection as a result of rendering template variables.
arguments = this.enrichFunctionArguments(kernel, fBlock,
arguments ==
null ? new DefaultKernelArguments()
: new DefaultKernelArguments(
arguments,
new HashMap<>()));
arguments == null
? new KernelFunctionArguments()
: new KernelFunctionArguments(arguments));
}
return kernel
@@ -148,14 +147,14 @@ public final class CodeBlock extends Block implements CodeRendering {
/// <param name="arguments">The prompt rendering arguments.</param>
/// <returns>The function arguments.</returns>
/// <exception cref="KernelException">Occurs when any argument other than the first is not a named argument.</exception>
private KernelArguments enrichFunctionArguments(
private KernelFunctionArguments enrichFunctionArguments(
Kernel kernel,
FunctionIdBlock fBlock,
KernelArguments arguments) {
KernelFunctionArguments arguments) {
Block firstArg = this.tokens.get(1);
// Get the function metadata
KernelFunctionMetadata functionMetadata = kernel.getPlugins()
KernelFunctionMetadata<?> functionMetadata = kernel.getPlugins()
.getFunction(fBlock.getPluginName(), fBlock.getFunctionName()).getMetadata();
// Check if the function has parameters to be set
@@ -2,7 +2,8 @@
package com.microsoft.semantickernel.templateengine.semantickernel.blocks;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import javax.annotation.Nullable;
import reactor.core.publisher.Mono;
@@ -18,5 +19,5 @@ public interface CodeRendering {
* @param arguments Optional arguments used to render the block
* @return Rendered content
*/
Mono<String> renderCodeAsync(Kernel kernel, @Nullable KernelArguments arguments);
Mono<String> renderCodeAsync(Kernel kernel, @Nullable KernelFunctionArguments arguments);
}
@@ -1,9 +1,10 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.templateengine.semantickernel.blocks;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
public final class FunctionIdBlock extends Block implements TextRendering {
private final String skillName;
@@ -31,7 +32,7 @@ public final class FunctionIdBlock extends Block implements TextRendering {
@Override
@Nullable
public String render(@Nullable KernelArguments variables) {
public String render(@Nullable KernelFunctionArguments variables) {
return this.getContent();
}
@@ -1,13 +1,14 @@
package com.microsoft.semantickernel.templateengine.semantickernel.blocks;
import static com.microsoft.semantickernel.templateengine.semantickernel.blocks.BlockTypes.NamedArg;
import com.microsoft.semantickernel.Verify;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.microsoft.semantickernel.Verify;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import static com.microsoft.semantickernel.templateengine.semantickernel.blocks.BlockTypes.NamedArg;
public class NamedArgBlock extends Block implements TextRendering {
private static final Logger LOGGER = LoggerFactory.getLogger(NamedArgBlock.class);
@@ -104,7 +105,7 @@ public class NamedArgBlock extends Block implements TextRendering {
}
@Override
public String render(@Nullable KernelArguments variables) {
public String render(@Nullable KernelFunctionArguments variables) {
return getContent();
}
@@ -120,7 +121,7 @@ public class NamedArgBlock extends Block implements TextRendering {
}
@SuppressWarnings("NullAway")
public String getValue(KernelArguments arguments) {
public String getValue(KernelFunctionArguments arguments) {
boolean valueIsValidValBlock = this.valBlock != null && this.valBlock.isValid();
if (valueIsValidValBlock) {
return this.valBlock.render(arguments);
@@ -1,9 +1,10 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.templateengine.semantickernel.blocks;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
public final class TextBlock extends Block implements TextRendering {
public TextBlock(String text) {
@@ -16,7 +17,7 @@ public final class TextBlock extends Block implements TextRendering {
}
@Override
public String render(@Nullable KernelArguments variables) {
public String render(@Nullable KernelFunctionArguments variables) {
return super.getContent();
}
@@ -1,9 +1,10 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.templateengine.semantickernel.blocks;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
/// <summary>
/// Interface of static blocks that don't need async IO to be rendered.
/// </summary>
@@ -14,5 +15,5 @@ public interface TextRendering {
/// <param name="variables">Optional variables used to render the block</param>
/// <returns>Rendered content</returns>
@Nullable
String render(@Nullable KernelArguments variables);
String render(@Nullable KernelFunctionArguments variables);
}
@@ -1,9 +1,11 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.templateengine.semantickernel.blocks;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import reactor.util.annotation.Nullable;
public final class ValBlock extends Block implements TextRendering {
@@ -31,7 +33,8 @@ public final class ValBlock extends Block implements TextRendering {
}
@Override
public String render(@Nullable KernelArguments variables) {
@Nullable
public String render(@Nullable KernelFunctionArguments variables) {
return value;
}
@@ -1,12 +1,14 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.templateengine.semantickernel.blocks;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.orchestration.contextvariables.KernelArguments;
import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.orchestration.contextvariables.ContextVariable;
import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException;
public final class VarBlock extends Block implements TextRendering {
@@ -24,7 +26,7 @@ public final class VarBlock extends Block implements TextRendering {
}
@Override
public String render(@Nullable KernelArguments variables) {
public String render(@Nullable KernelFunctionArguments variables) {
if (variables == null) {
return "";
}
@@ -1,13 +1,15 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.templateengine.semantickernel;
import com.microsoft.semantickernel.orchestration.contextvariables.DefaultKernelArguments;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import com.microsoft.semantickernel.orchestration.KernelFunctionArguments;
import com.microsoft.semantickernel.templateengine.semantickernel.blocks.Block;
import com.microsoft.semantickernel.templateengine.semantickernel.blocks.FunctionIdBlock;
import com.microsoft.semantickernel.templateengine.semantickernel.blocks.NamedArgBlock;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class CodeTokenizerTest {
@@ -25,19 +27,19 @@ public class CodeTokenizerTest {
NamedArgBlock namedArgBlock = (NamedArgBlock) tokens.get(1);
Assertions.assertEquals("street", namedArgBlock.getName());
Assertions.assertEquals("123 Main St", namedArgBlock.getValue(
new DefaultKernelArguments.Builder()
new KernelFunctionArguments.Builder()
.withVariable("street", "123 Main St")
.build()));
namedArgBlock = (NamedArgBlock) tokens.get(2);
Assertions.assertEquals("zip", namedArgBlock.getName());
Assertions.assertEquals("98123", namedArgBlock.getValue(
new DefaultKernelArguments.Builder().build()));
new KernelFunctionArguments.Builder().build()));
namedArgBlock = (NamedArgBlock) tokens.get(3);
Assertions.assertEquals("city", namedArgBlock.getName());
Assertions.assertEquals("Seattle", namedArgBlock.getValue(
new DefaultKernelArguments.Builder().build()));
new KernelFunctionArguments.Builder().build()));
}
@Test
@@ -54,7 +56,7 @@ public class CodeTokenizerTest {
NamedArgBlock namedArgBlock = (NamedArgBlock) tokens.get(1);
Assertions.assertEquals("recall", namedArgBlock.getName());
Assertions.assertEquals("where did I grow up?", namedArgBlock.getValue(
new DefaultKernelArguments.Builder()
new KernelFunctionArguments.Builder()
.build()));
}
}