mirror of
https://github.com/microsoft/semantic-kernel.git
synced 2026-10-12 02:19:06 +00:00
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:
+1
-1
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+7
-2
@@ -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);
|
||||
|
||||
+1
-1
@@ -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();
|
||||
|
||||
+7
-6
@@ -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());
|
||||
|
||||
-1
@@ -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());
|
||||
}
|
||||
|
||||
+3
-3
@@ -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();
|
||||
|
||||
|
||||
-10
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -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);
|
||||
|
||||
|
||||
+1
-2
@@ -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?")
|
||||
|
||||
+3
-1
@@ -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,
|
||||
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
|
||||
+1
-2
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-2
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-4
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+30
-6
@@ -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,
|
||||
|
||||
+3
-3
@@ -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;
|
||||
|
||||
+45
@@ -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.
|
||||
*
|
||||
|
||||
+7
-4
@@ -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;
|
||||
}
|
||||
|
||||
+22
-2
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+2
-2
@@ -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,
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ public class HandlebarsPromptTemplate implements PromptTemplate {
|
||||
template);
|
||||
|
||||
if (arguments == null) {
|
||||
arguments = new KernelFunctionArguments();
|
||||
arguments = KernelFunctionArguments.builder().build();
|
||||
}
|
||||
return handler.render(arguments);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user