Java: Implement a number of fixes from API review (#5201)

- Make constructors on classes that have builders protected
- Remove the addPlugin function from the kernel to make plugin set
immutable, in favour of adding a copy method for creating a clone of a
kernel that can have plugins added, i.e:
```
        kernel = kernel.copy()
                             .withPlugin(timePlugin)
                             .build()
```
- Add sync invocation methods in addition to async
- Add warning if `FunctionInvocation` is used in an unusual manner that
might indicate a bug
This commit is contained in:
John Oliver
2024-02-27 15:34:12 -05:00
committed by GitHub
parent d3722939dc
commit bc9d4cba11
26 changed files with 237 additions and 88 deletions
@@ -57,7 +57,7 @@ public class OpenAIChatCompletion implements ChatCompletionService {
private final String serviceId;
private final String modelId;
public OpenAIChatCompletion(
protected OpenAIChatCompletion(
OpenAIAsyncClient client,
String modelId,
@Nullable String serviceId) {
@@ -40,7 +40,7 @@ public class OpenAITextGenerationService implements TextGenerationService {
/// <param name="modelId">Azure OpenAI model id, see https://learn.microsoft.com/azure/cognitive-services/openai/how-to/create-resource</param>
/// <param name="httpClient">Custom <see cref="HttpClient"/> for HTTP requests.</param>
/// <param name="loggerFactory">The <see cref="ILoggerFactory"/> to use for logging. If null, no logging will be performed.</param>
public OpenAITextGenerationService(
protected OpenAITextGenerationService(
OpenAIAsyncClient client,
String modelId,
@Nullable String serviceId) {
@@ -58,7 +58,9 @@ public class Example06_TemplateLanguage {
KernelPlugin time = KernelPluginFactory.createFromObject(
new Time(), "time");
kernel.addPlugin(time);
kernel = kernel.toBuilder()
.withPlugin(time)
.build();
// Prompt Function invoking time.Date and time.Time method functions
String functionDefinition = """
@@ -74,7 +76,10 @@ public class Example06_TemplateLanguage {
System.out.println("--- Rendered Prompt");
var promptTemplate = new KernelPromptTemplateFactory()
.tryCreate(new PromptTemplateConfig(functionDefinition));
.tryCreate(PromptTemplateConfig
.builder()
.withTemplate(functionDefinition)
.build());
var renderedPrompt = promptTemplate.renderAsync(kernel, null, null).block();
System.out.println(renderedPrompt);
@@ -178,7 +178,7 @@ public class Example07_BingAndGooglePlugins {
// If the answer contains commands, execute them using the prompt renderer.
if (result.contains("bing.search")) {
PromptTemplate promptTemplate = new KernelPromptTemplateFactory()
.tryCreate(new PromptTemplateConfig(result));
.tryCreate(PromptTemplateConfig.builder().withTemplate(result).build());
System.out.println("---- Fetching information from Bing...");
var information = promptTemplate.renderAsync(kernel, null, null).block();
@@ -9,6 +9,7 @@ import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.core.credential.AzureKeyCredential;
import com.azure.core.credential.KeyCredential;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.Kernel.Builder;
import com.microsoft.semantickernel.aiservices.openai.textcompletion.OpenAITextGenerationService;
import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
@@ -57,20 +58,19 @@ public class Example10_DescribeAllPluginsAndFunctions {
.withModelId(MODEL_ID)
.build();
Kernel kernel = Kernel.builder()
.withAIService(TextGenerationService.class, textGenerationService)
.build();
Builder kernelBuilder = Kernel.builder()
.withAIService(TextGenerationService.class, textGenerationService);
kernel.addPlugin(
kernelBuilder.withPlugin(
KernelPluginFactory.createFromObject(
new StaticTextPlugin(), "StaticTextPlugin"));
// Import another native plugin
kernel.addPlugin(
kernelBuilder.withPlugin(
KernelPluginFactory.createFromObject(
new TextPlugin(), "AnotherTextPlugin"));
kernel.addPlugin(
kernelBuilder.withPlugin(
KernelPluginFactory
.importPluginFromDirectory(
Path.of(PLUGIN_DIR, "java/samples/sample-code/src/main/resources/Plugins"),
@@ -102,6 +102,7 @@ public class Example10_DescribeAllPluginsAndFunctions {
System.out.println("**********************************************");
System.out.println();
Kernel kernel = kernelBuilder.build();
kernel.getPlugins()
.forEach(plugin -> {
System.out.println("Plugin: " + plugin.getName());
@@ -166,7 +166,6 @@ public class Example13_ConversationSummaryPlugin {
new Builder()
.withInput(chatTranscript)
.build());
System.out.println("Generated Action Items:");
System.out.println(summary.block().getResult());
}
@@ -77,7 +77,7 @@ public class Example30_ChatWithPrompts {
// We could also use a variable, this is just to show that the prompt can invoke functions.
KernelPlugin timePlugin = KernelPluginFactory.createFromObject(
new TimePlugin(), "time");
kernel.addPlugin(timePlugin);
kernel = kernel.toBuilder().withPlugin(timePlugin).build();
// Adding required arguments referenced by the prompt templates.
@@ -92,7 +92,7 @@ public class Example30_ChatWithPrompts {
// Render the system prompt. This string is used to configure the chat.
// This contains the context, ie a piece of a wikipedia page selected by the user.
String systemMessage = PromptTemplateFactory
.build(new PromptTemplateConfig(systemPromptTemplate))
.build(PromptTemplateConfig.builder().withTemplate(systemPromptTemplate).build())
.renderAsync(kernel, arguments, null)
.block();
@@ -101,7 +101,7 @@ public class Example30_ChatWithPrompts {
// Render the user prompt. This string is the query sent by the user
// This contains the user request, ie "extract locations as a bullet point list"
String userMessage = PromptTemplateFactory
.build(new PromptTemplateConfig(userPromptTemplate))
.build(PromptTemplateConfig.builder().withTemplate(userPromptTemplate).build())
.renderAsync(kernel, arguments, null)
.block();
@@ -9,10 +9,8 @@ import com.azure.core.http.HttpClient;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.plugin.KernelPluginFactory;
import com.microsoft.semantickernel.samples.plugins.ConversationSummaryPlugin;
import com.microsoft.semantickernel.services.OrderedAIServiceSelector;
import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService;
import com.microsoft.semantickernel.services.textcompletion.TextGenerationService;
import java.util.ArrayList;
public class Example42_KernelBuilder {
@@ -62,13 +60,5 @@ public class Example42_KernelBuilder {
"ConversationSummaryPlugin"))
.build();
/////////////////////////////////////////////////////////
// KernelBuilder provides a convenient API for creating Kernel instances. However, it is just a
// wrapper, ultimately constructing a Kernel
// using the public constructor that's available for anyone to use directly if desired.
Kernel kernel = new Kernel(
new OrderedAIServiceSelector(),
new ArrayList<>(),
null);
}
}
@@ -59,7 +59,9 @@ public class Example56_TemplateMethodFunctionsWithMultipleArguments {
// Load native plugin into the kernel function collection, sharing its functions with prompt templates
// Functions loaded here are available as "text.*"
kernel.addPlugin(KernelPluginFactory.createFromObject(new TextPlugin(), "text"));
kernel = kernel.toBuilder()
.withPlugin(KernelPluginFactory.createFromObject(new TextPlugin(), "text"))
.build();
// Prompt Function invoking text.Concat method function with named arguments input and input2 where input is a string and input2 is set to a variable from context called word2.
String functionDefinition = "Write a haiku about the following: {{text.Concat input='Harry' input2=$word2}}";
@@ -68,7 +70,7 @@ public class Example56_TemplateMethodFunctionsWithMultipleArguments {
System.out.println("--- Rendered Prompt");
var promptTemplateFactory = new KernelPromptTemplateFactory();
var promptTemplate = promptTemplateFactory.tryCreate(
new PromptTemplateConfig(functionDefinition));
PromptTemplateConfig.builder().withTemplate(functionDefinition).build());
var renderedPrompt = promptTemplate.renderAsync(kernel, arguments, null).block();
System.out.println(renderedPrompt);
@@ -54,10 +54,9 @@ public class Example59_OpenAIFunctionCalling {
var kernel = Kernel.builder()
.withAIService(ChatCompletionService.class, chat)
.withPlugin(plugin)
.build();
kernel.addPlugin(plugin);
var function = KernelFunctionFromPrompt.builder()
.withTemplate(
"What is the probable current color of the sky in Thrapston?")
@@ -22,7 +22,9 @@ public class Example60_AdvancedMethodFunctions {
new FunctionsChainingPlugin(),
FunctionsChainingPlugin.PluginName);
kernel.addPlugin(functions);
kernel = kernel.toBuilder()
.withPlugin(functions)
.build();
ContextVariableTypeConverter<MyCustomType> type = new ContextVariableTypeConverter<>(
MyCustomType.class,
@@ -23,9 +23,9 @@ public class Example69_MutableKernelPlugin {
.withFunctionName("dateFunction")
.build());
Kernel kernel = Kernel.builder().build();
kernel.addPlugin(plugin);
Kernel kernel = Kernel.builder()
.withPlugin(plugin)
.build();
var result = kernel.invokeAsync(kernel.getFunction("Plugin", "dateFunction"))
.block();
@@ -6,6 +6,7 @@ import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.contextvariables.ContextVariableType;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.orchestration.FunctionInvocation;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.InvocationContext;
import com.microsoft.semantickernel.plugin.KernelPlugin;
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
@@ -36,21 +37,38 @@ public class Kernel implements Buildable {
private final KernelPluginCollection plugins;
private final KernelHooks globalKernelHooks;
// Only present so we can create a builder in copy method
private final AIServiceCollection services;
private final Function<AIServiceCollection, AIServiceSelector> serviceSelectorProvider;
/**
* Initializes a new instance of {@code Kernel}.
*
* @param serviceSelector The {@code AIServiceSelector} used to query for services available
* through the kernel.
* @param plugins The collection of plugins available through the kernel. If
* {@code null}, an empty collection will be used.
* @param globalKernelHooks The global hooks to be used throughout the kernel. If {@code null},
* an empty collection will be used.
* @param services The collection of services available through the kernel.
* @param serviceSelectorProvider The service selector provider for the kernel. If {@code null},
* an ordered service selector will be used.
* @param plugins The collection of plugins available through the kernel. If
* {@code null}, an empty collection will be used.
* @param globalKernelHooks The global hooks to be used throughout the kernel. If
* {@code null}, an empty collection will be used.
*/
public Kernel(
AIServiceSelector serviceSelector,
AIServiceCollection services,
Function<AIServiceCollection, AIServiceSelector> serviceSelectorProvider,
@Nullable List<KernelPlugin> plugins,
@Nullable KernelHooks globalKernelHooks) {
this.services = services;
this.serviceSelectorProvider = serviceSelectorProvider;
AIServiceSelector serviceSelector;
if (serviceSelectorProvider == null) {
serviceSelector = new OrderedAIServiceSelector(services);
} else {
serviceSelector = serviceSelectorProvider.apply(services);
}
this.serviceSelector = serviceSelector;
if (plugins != null) {
this.plugins = new KernelPluginCollection(plugins);
} else {
@@ -65,10 +83,34 @@ public class Kernel implements Buildable {
*
* @return The fluent builder for creating a new instance of {@code Kernel}.
*/
public static Kernel.Builder builder() {
public static Builder builder() {
return new Kernel.Builder();
}
/**
* Creates a Builder that can create a copy of the {@code Kernel}. Use this method if you wish
* to modify the state of the kernel such as adding new plugins or services.
*
* @param kernel The kernel to copy.
* @return A Builder that can create a copy of the instance of {@code Kernel}.
*/
public static Builder from(Kernel kernel) {
return new Builder(
kernel.services,
kernel.serviceSelectorProvider,
kernel.plugins);
}
/**
* Creates a Builder that can create a copy of the current instance of {@code Kernel}. Use this
* method if you wish to modify the state of the kernel such as adding new plugins or services.
*
* @return A Builder that can create a copy of the current instance of {@code Kernel}.
*/
public Builder toBuilder() {
return new Builder(services, serviceSelectorProvider, plugins);
}
/**
* Invokes a {@code KernelFunction} function by name.
*
@@ -88,6 +130,24 @@ public class Kernel implements Buildable {
return invokeAsync(function);
}
/**
* Invokes a {@code KernelFunction} function by name.
*
* @param <T> The return type of the function.
* @param pluginName The name of the plugin containing the function.
* @param functionName The name of the function to invoke.
* @return The result of the function invocation.
* @throws IllegalArgumentException if the plugin or function is not found.
* @see KernelFunction#invokeAsync(Kernel)
* @see KernelPluginCollection#getFunction(String, String)
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public <T> FunctionResult<T> invoke(
String pluginName,
String functionName) {
return this.<T>invokeAsync(pluginName, functionName).block();
}
/**
* Invokes a {@code KernelFunction}.
*
@@ -101,15 +161,15 @@ public class Kernel implements Buildable {
}
/**
* This method is used to add plugins to the kernel after it has been created. If a plugin with
* the same name already exists, it will be replaced.
* Invokes a {@code KernelFunction}.
*
* @param plugin The plugin to add.
* @return {@code this} kernel with the plugin added.
* @param <T> The return type of the function.
* @param function The function to invoke.
* @return The result of the function invocation.
* @see KernelFunction#invokeAsync(Kernel)
*/
public Kernel addPlugin(KernelPlugin plugin) {
plugins.add(plugin);
return this;
public <T> FunctionResult<T> invoke(KernelFunction<T> function) {
return invokeAsync(function).block();
}
/**
@@ -216,6 +276,18 @@ public class Kernel implements Buildable {
@Nullable
private Function<AIServiceCollection, AIServiceSelector> serviceSelectorProvider;
public Builder() {
}
private Builder(
AIServiceCollection services,
@Nullable Function<AIServiceCollection, AIServiceSelector> serviceSelectorProvider,
KernelPluginCollection plugins) {
this.services.putAll(services);
this.serviceSelectorProvider = serviceSelectorProvider;
this.plugins.addAll(plugins.getPlugins());
}
/**
* Adds a service to the kernel.
*
@@ -259,16 +331,9 @@ public class Kernel implements Buildable {
*/
@Override
public Kernel build() {
AIServiceSelector serviceSelector;
if (serviceSelectorProvider == null) {
serviceSelector = new OrderedAIServiceSelector(services);
} else {
serviceSelector = serviceSelectorProvider.apply(services);
}
return new Kernel(
serviceSelector,
services,
serviceSelectorProvider,
plugins,
null);
}
@@ -31,8 +31,7 @@ public class FunctionInvokedEvent<T> implements KernelHookEvent {
@Nullable KernelFunctionArguments arguments,
FunctionResult<T> result) {
this.function = function;
this.arguments = arguments != null ? new KernelFunctionArguments(arguments)
: new KernelFunctionArguments();
this.arguments = KernelFunctionArguments.builder().withVariables(arguments).build();
this.result = result;
}
@@ -27,8 +27,7 @@ public class FunctionInvokingEvent<T> implements KernelHookEvent {
public FunctionInvokingEvent(KernelFunction<T> function,
@Nullable KernelFunctionArguments arguments) {
this.function = function;
this.arguments = arguments != null ? new KernelFunctionArguments(arguments)
: new KernelFunctionArguments();
this.arguments = KernelFunctionArguments.builder().withVariables(arguments).build();
}
/**
@@ -27,8 +27,7 @@ public class PromptRenderedEvent implements KernelHookEvent {
@Nullable KernelFunctionArguments arguments,
String prompt) {
this.function = function;
this.arguments = arguments != null ? new KernelFunctionArguments(arguments)
: new KernelFunctionArguments();
this.arguments = KernelFunctionArguments.builder().withVariables(arguments).build();
this.prompt = prompt;
}
@@ -23,8 +23,7 @@ public class PromptRenderingEvent implements KernelHookEvent {
public PromptRenderingEvent(KernelFunction<?> function,
@Nullable KernelFunctionArguments arguments) {
this.function = function;
this.arguments = arguments != null ? new KernelFunctionArguments(arguments)
: new KernelFunctionArguments();
this.arguments = KernelFunctionArguments.builder().withVariables(arguments).build();
}
/**
@@ -95,7 +95,7 @@ public final class CodeBlock extends Block implements CodeRendering {
}
if (context == null) {
context = new InvocationContext();
context = InvocationContext.builder().build();
}
// this.Log.LogTrace("Rendering code: `{0}`", this.Content);
@@ -138,9 +138,7 @@ 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 KernelFunctionArguments()
: new KernelFunctionArguments(arguments),
KernelFunctionArguments.builder().withVariables(arguments).build(),
context);
}
@@ -46,6 +46,8 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
@Nullable
protected UnmodifiableToolCallBehavior toolCallBehavior;
private boolean isSubscribed = false;
/**
* Create a new function invocation.
*
@@ -101,7 +103,7 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
function
.invokeAsync(
kernel,
new KernelFunctionArguments(arguments),
KernelFunctionArguments.builder().withVariables(arguments).build(),
null,
new InvocationContext(context))
.handle(convertToType(variableType))
@@ -162,11 +164,8 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
*/
public FunctionInvocation<T> withArguments(
@Nullable KernelFunctionArguments arguments) {
if (arguments == null) {
this.arguments = null;
} else {
this.arguments = new KernelFunctionArguments(arguments);
}
logSubscribeWarning();
this.arguments = KernelFunctionArguments.builder().withVariables(arguments).build();
return this;
}
@@ -178,6 +177,7 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
* @return A new {@code FunctionInvocation} for fluent chaining.
*/
public <U> FunctionInvocation<U> withResultType(ContextVariableType<U> resultType) {
logSubscribeWarning();
return new FunctionInvocation<>(
kernel,
function,
@@ -198,6 +198,7 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
if (hook == null) {
return this;
}
logSubscribeWarning();
KernelHooks clone = new KernelHooks(this.hooks);
clone.addHook(hook);
this.hooks = unmodifiableClone(clone);
@@ -215,6 +216,7 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
if (hooks == null) {
return this;
}
logSubscribeWarning();
this.hooks = unmodifiableClone(new KernelHooks(this.hooks).addHooks(hooks));
return this;
}
@@ -228,6 +230,7 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
*/
public FunctionInvocation<T> withPromptExecutionSettings(
@Nullable PromptExecutionSettings promptExecutionSettings) {
logSubscribeWarning();
this.promptExecutionSettings = promptExecutionSettings;
return this;
}
@@ -239,6 +242,7 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
* @return this {@code FunctionInvocation} for fluent chaining.
*/
public FunctionInvocation<T> withToolCallBehavior(@Nullable ToolCallBehavior toolCallBehavior) {
logSubscribeWarning();
this.toolCallBehavior = unmodifiableClone(toolCallBehavior);
return this;
}
@@ -250,6 +254,7 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
* @return this {@code FunctionInvocation} for fluent chaining.
*/
public FunctionInvocation<T> withTypeConverter(ContextVariableTypeConverter<?> typeConverter) {
logSubscribeWarning();
contextVariableTypes.putConverter(typeConverter);
return this;
}
@@ -261,6 +266,7 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
* @return this {@code FunctionInvocation} for fluent chaining.
*/
public FunctionInvocation<T> withTypes(ContextVariableTypes contextVariableTypes) {
logSubscribeWarning();
this.contextVariableTypes.putConverters(contextVariableTypes);
return this;
}
@@ -277,6 +283,7 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
if (invocationContext == null) {
return this;
}
logSubscribeWarning();
withTypes(invocationContext.getContextVariableTypes());
withToolCallBehavior(invocationContext.getToolCallBehavior());
withPromptExecutionSettings(invocationContext.getPromptExecutionSettings());
@@ -284,6 +291,14 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
return this;
}
private void logSubscribeWarning() {
if (isSubscribed) {
LOGGER.warn(
"Attempting to modify function {}.{} after it has already been subscribed to. This is not necessarily an error but may be an unusual pattern and indicate a potential bug.",
function.getPluginName(), function.getName());
}
}
/**
* This method hanldes the reactive stream when the KernelFunciton is invoked.
*
@@ -291,6 +306,15 @@ public class FunctionInvocation<T> extends Mono<FunctionResult<T>> {
*/
@Override
public void subscribe(CoreSubscriber<? super FunctionResult<T>> coreSubscriber) {
if (isSubscribed) {
LOGGER.warn(
"Function {}.{} has already been subscribed to. This is not necessarily an error but may be an unusual pattern.",
function.getPluginName(), function.getName());
}
isSubscribed = true;
performSubscribe(
coreSubscriber,
kernel,
@@ -34,7 +34,7 @@ public class InvocationContext implements Buildable {
* @param toolCallBehavior The behavior for tool calls.
* @param contextVariableTypes The types of context variables.
*/
public InvocationContext(
protected InvocationContext(
@Nullable KernelHooks hooks,
@Nullable PromptExecutionSettings promptExecutionSettings,
@Nullable ToolCallBehavior toolCallBehavior,
@@ -52,7 +52,7 @@ public class InvocationContext implements Buildable {
/**
* Create a new instance of InvocationContext.
*/
public InvocationContext() {
protected InvocationContext() {
this.hooks = null;
this.promptExecutionSettings = null;
this.toolCallBehavior = null;
@@ -64,7 +64,7 @@ public class InvocationContext implements Buildable {
*
* @param context The context to copy.
*/
public InvocationContext(@Nullable InvocationContext context) {
protected InvocationContext(@Nullable InvocationContext context) {
if (context == null) {
this.hooks = null;
this.promptExecutionSettings = null;
@@ -191,6 +191,40 @@ public abstract class KernelFunction<T> implements Buildable {
@Nullable ContextVariableType<T> variableType,
@Nullable InvocationContext invocationContext);
/**
* Invokes this KernelFunction.
* <p>
* If the {@code variableType} parameter is provided, the {@link ContextVariableType} is used to
* convert the result of the function to the appropriate {@link FunctionResult}. 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 global KernelHooks
* (if any) to the {@link InvocationContext}. Calling {@code KernelFunction.invokeAsync}
* directly does not add the global hooks.
*
* @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}
* @param invocationContext The arguments to pass to the function's invocation
* @return The result of the function's execution.
* @see FunctionResult#getResultVariable()
*/
public FunctionResult<T> invoke(
Kernel kernel,
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> variableType,
@Nullable InvocationContext invocationContext) {
return invokeAsync(kernel, arguments, variableType, invocationContext).block();
}
/**
* Invokes this KernelFunction.
*
@@ -202,6 +236,17 @@ public abstract class KernelFunction<T> implements Buildable {
return new FunctionInvocation<>(kernel, this);
}
/**
* Invokes this KernelFunction.
*
* @param kernel The Kernel containing services, plugins, and other state for use throughout the
* operation.
* @return The result of the function's execution.
*/
public FunctionResult<T> invoke(Kernel kernel) {
return invokeAsync(kernel).block();
}
/**
* Builder for creating a {@link KernelFunction} from a prompt.
*
@@ -32,7 +32,7 @@ public class KernelFunctionArguments implements Buildable, Map<String, ContextVa
*
* @param variables The variables to use for the function invocation.
*/
public KernelFunctionArguments(
protected KernelFunctionArguments(
@Nullable Map<String, ContextVariable<?>> variables) {
if (variables == null) {
this.variables = new CaseInsensitiveMap<>();
@@ -46,7 +46,7 @@ public class KernelFunctionArguments implements Buildable, Map<String, ContextVa
*
* @param content The content to use for the function invocation.
*/
public KernelFunctionArguments(@NonNull ContextVariable<?> content) {
protected KernelFunctionArguments(@NonNull ContextVariable<?> content) {
this.variables = new CaseInsensitiveMap<>();
this.variables.put(MAIN_KEY, content);
}
@@ -54,7 +54,7 @@ public class KernelFunctionArguments implements Buildable, Map<String, ContextVa
/**
* Create a new instance of KernelFunctionArguments.
*/
public KernelFunctionArguments() {
protected KernelFunctionArguments() {
this.variables = new CaseInsensitiveMap<>();
}
@@ -257,7 +257,10 @@ public class KernelFunctionArguments implements Buildable, Map<String, ContextVa
* @param map Existing variables
* @return {$code this} Builder for fluent coding
*/
public Builder withVariables(Map<String, ContextVariable<?>> map) {
public Builder withVariables(@Nullable Map<String, ContextVariable<?>> map) {
if (map == null) {
return this;
}
variables.putAll(map);
return this;
}
@@ -563,7 +563,7 @@ public class KernelFunctionFromMethod<T> extends KernelFunction<T> implements Bu
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> variableType,
@Nullable InvocationContext invocationContext) {
return function.invoke(kernel, this, arguments, variableType, invocationContext);
return function.invokeAsync(kernel, this, arguments, variableType, invocationContext);
}
/**
@@ -581,12 +581,32 @@ public class KernelFunctionFromMethod<T> extends KernelFunction<T> implements Bu
* @param invocationContext the invocation context
* @return a {@link Mono} that emits the result of the function invocation
*/
Mono<FunctionResult<T>> invoke(
Mono<FunctionResult<T>> invokeAsync(
Kernel kernel,
KernelFunction<T> function,
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> variableType,
@Nullable InvocationContext invocationContext);
/**
* Invokes the function.
*
* @param kernel the kernel to invoke the function on
* @param function the function to invoke
* @param arguments the arguments to the function
* @param variableType the variable type of the function
* @param invocationContext the invocation context
* @return a {@link Mono} that emits the result of the function invocation
*/
default FunctionResult<T> invoke(
Kernel kernel,
KernelFunction<T> function,
@Nullable KernelFunctionArguments arguments,
@Nullable ContextVariableType<T> variableType,
@Nullable InvocationContext invocationContext) {
return invokeAsync(kernel, function, arguments, variableType,
invocationContext).block();
}
}
/**
@@ -48,7 +48,7 @@ public class KernelFunctionFromPrompt<T> extends KernelFunction<T> {
* @param promptConfig the configuration for the prompt
* @param executionSettings the execution settings to use when invoking the function
*/
public KernelFunctionFromPrompt(
protected KernelFunctionFromPrompt(
PromptTemplate template,
PromptTemplateConfig promptConfig,
@Nullable Map<String, PromptExecutionSettings> executionSettings) {
@@ -56,7 +56,7 @@ public class PromptTemplateConfig implements Buildable {
*
* @param template Template string
*/
public PromptTemplateConfig(String template) {
protected PromptTemplateConfig(String template) {
this(
CURRENT_SCHEMA,
DEFAULT_CONFIG_NAME,
@@ -121,7 +121,7 @@ public class PromptTemplateConfig implements Buildable {
* @param outputVariable Output variable
* @param executionSettings Execution settings
*/
public PromptTemplateConfig(
protected PromptTemplateConfig(
@Nullable String name,
@Nullable String template,
@Nullable String templateFormat,
@@ -68,7 +68,7 @@ public class HandlebarsPromptTemplate implements PromptTemplate {
template);
if (arguments == null) {
arguments = new KernelFunctionArguments();
arguments = KernelFunctionArguments.builder().build();
}
return handler.render(arguments);
}