> messages = new ArrayList<>();
+ if (message != null) {
+ messages.add(message);
+ }
+ return invokeAsync(messages, thread, options);
+ }
+}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/AutoFunctionChoiceBehavior.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/AutoFunctionChoiceBehavior.java
new file mode 100644
index 000000000..b4993f44c
--- /dev/null
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/AutoFunctionChoiceBehavior.java
@@ -0,0 +1,40 @@
+// Copyright (c) Microsoft. All rights reserved.
+package com.microsoft.semantickernel.functionchoice;
+
+import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
+
+import javax.annotation.Nullable;
+import java.util.List;
+
+/**
+ * A set of allowed kernel functions. All kernel functions are allowed if allKernelFunctionsAllowed is true.
+ * Otherwise, only the functions in allowedFunctions are allowed.
+ *
+ * If a function is allowed, it may be called. If it is not allowed, it will not be called.
+ */
+public class AutoFunctionChoiceBehavior extends FunctionChoiceBehavior {
+ private final boolean autoInvoke;
+
+ /**
+ * Create a new instance of AutoFunctionChoiceBehavior.
+ *
+ * @param autoInvoke Whether auto-invocation is enabled.
+ * @param functions A set of functions to advertise to the model.
+ * @param options Options for the function choice behavior.
+ */
+ public AutoFunctionChoiceBehavior(boolean autoInvoke,
+ @Nullable List> functions,
+ @Nullable FunctionChoiceBehaviorOptions options) {
+ super(functions, options);
+ this.autoInvoke = autoInvoke;
+ }
+
+ /**
+ * Check whether the given function is allowed.
+ *
+ * @return Whether the function is allowed.
+ */
+ public boolean isAutoInvoke() {
+ return autoInvoke;
+ }
+}
\ No newline at end of file
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/FunctionChoiceBehavior.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/FunctionChoiceBehavior.java
new file mode 100644
index 000000000..f00249524
--- /dev/null
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/FunctionChoiceBehavior.java
@@ -0,0 +1,201 @@
+// Copyright (c) Microsoft. All rights reserved.
+package com.microsoft.semantickernel.functionchoice;
+
+import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
+
+import javax.annotation.Nullable;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Defines the behavior of a tool call. Currently, the only tool available is function calling.
+ */
+public abstract class FunctionChoiceBehavior {
+ private final Set fullFunctionNames;
+
+ protected final List> functions;
+ protected final FunctionChoiceBehaviorOptions options;
+
+ protected FunctionChoiceBehavior(@Nullable List> functions,
+ @Nullable FunctionChoiceBehaviorOptions options) {
+ this.functions = functions != null ? Collections.unmodifiableList(functions) : null;
+ this.fullFunctionNames = new HashSet<>();
+
+ if (functions != null) {
+ functions.stream().filter(Objects::nonNull).forEach(
+ f -> this.fullFunctionNames
+ .add(formFullFunctionName(f.getPluginName(), f.getName())));
+ }
+
+ if (options != null) {
+ this.options = options;
+ } else {
+ this.options = FunctionChoiceBehaviorOptions.builder().build();
+ }
+ }
+
+ /**
+ * Gets the functions that are allowed.
+ *
+ * @return The functions that are allowed.
+ */
+ public List> getFunctions() {
+ return Collections.unmodifiableList(functions);
+ }
+
+ /**
+ * Gets the options for the function choice behavior.
+ *
+ * @return The options for the function choice behavior.
+ */
+ public FunctionChoiceBehaviorOptions getOptions() {
+ return options;
+ }
+
+ /**
+ * Gets an instance of the FunctionChoiceBehavior that provides all the Kernel's plugins functions to the AI model to call.
+ *
+ * @param autoInvoke Indicates whether the functions should be automatically invoked by AI connectors
+ *
+ * @return A new ToolCallBehavior instance with all kernel functions allowed.
+ */
+ public static FunctionChoiceBehavior auto(boolean autoInvoke) {
+ return new AutoFunctionChoiceBehavior(autoInvoke, null, null);
+ }
+
+ /**
+ * Gets an instance of the FunctionChoiceBehavior that provides either all the Kernel's plugins functions to the AI model to call or specific functions.
+ *
+ * @param autoInvoke Enable or disable auto-invocation.
+ * If auto-invocation is enabled, the model may request that the Semantic Kernel
+ * invoke the kernel functions and return the value to the model.
+ * @param functions Functions to provide to the model. If null, all the Kernel's plugins' functions are provided to the model.
+ * If empty, no functions are provided to the model, which is equivalent to disabling function calling.
+ *
+ * @return A new FunctionChoiceBehavior instance with all kernel functions allowed.
+ */
+ public static FunctionChoiceBehavior auto(boolean autoInvoke,
+ @Nullable List> functions) {
+ return new AutoFunctionChoiceBehavior(autoInvoke, functions, null);
+ }
+
+ /**
+ * Gets an instance of the FunctionChoiceBehavior that provides either all the Kernel's plugins functions to the AI model to call or specific functions.
+ *
+ * @param autoInvoke Enable or disable auto-invocation.
+ * If auto-invocation is enabled, the model may request that the Semantic Kernel
+ * invoke the kernel functions and return the value to the model.
+ * @param functions Functions to provide to the model. If null, all the Kernel's plugins' functions are provided to the model.
+ * If empty, no functions are provided to the model, which is equivalent to disabling function calling.
+ * @param options Options for the function choice behavior.
+ *
+ * @return A new FunctionChoiceBehavior instance with all kernel functions allowed.
+ */
+ public static FunctionChoiceBehavior auto(boolean autoInvoke,
+ @Nullable List> functions,
+ @Nullable FunctionChoiceBehaviorOptions options) {
+ return new AutoFunctionChoiceBehavior(autoInvoke, functions, options);
+ }
+
+ /**
+ * Gets an instance of the FunctionChoiceBehavior that provides either all the Kernel's plugins functions to the AI model to call or specific functions.
+ *
+ * This behavior forces the model to call the provided functions.
+ * SK connectors will invoke a requested function or multiple requested functions if the model requests multiple ones in one request,
+ * while handling the first request, and stop advertising the functions for the following requests to prevent the model from repeatedly calling the same function(s).
+ *
+ * @return A new FunctionChoiceBehavior instance with the required function.
+ */
+ public static FunctionChoiceBehavior required(boolean autoInvoke,
+ @Nullable List> functions) {
+ return new RequiredFunctionChoiceBehavior(autoInvoke, functions, null);
+ }
+
+ /**
+ * Gets an instance of the FunctionChoiceBehavior that provides either all the Kernel's plugins functions to the AI model to call or specific functions.
+ *
+ * This behavior forces the model to call the provided functions.
+ * SK connectors will invoke a requested function or multiple requested functions if the model requests multiple ones in one request,
+ * while handling the first request, and stop advertising the functions for the following requests to prevent the model from repeatedly calling the same function(s).
+ *
+ * @param functions Functions to provide to the model. If null, all the Kernel's plugins' functions are provided to the model.
+ * If empty, no functions are provided to the model, which is equivalent to disabling function calling.
+ * @return A new FunctionChoiceBehavior instance with the required function.
+ */
+ public static FunctionChoiceBehavior required(boolean autoInvoke,
+ @Nullable List> functions,
+ @Nullable FunctionChoiceBehaviorOptions options) {
+ return new RequiredFunctionChoiceBehavior(autoInvoke, functions, options);
+ }
+
+ /**
+ * Gets an instance of the FunctionChoiceBehavior that provides either all the Kernel's plugins functions to the AI model to call or specific functions.
+ *
+ * This behavior is useful if the user should first validate what functions the model will use.
+ */
+ public static FunctionChoiceBehavior none() {
+ return new NoneFunctionChoiceBehavior(null, null);
+ }
+
+ /**
+ * Gets an instance of the FunctionChoiceBehavior that provides either all the Kernel's plugins functions to the AI model to call or specific functions.
+ *
+ * This behavior is useful if the user should first validate what functions the model will use.
+ *
+ * @param functions Functions to provide to the model. If null, all the Kernel's plugins' functions are provided to the model.
+ * If empty, no functions are provided to the model, which is equivalent to disabling function calling.
+ */
+ public static FunctionChoiceBehavior none(@Nullable List> functions,
+ @Nullable FunctionChoiceBehaviorOptions options) {
+ return new NoneFunctionChoiceBehavior(functions, options);
+ }
+
+ /**
+ * The separator between the plugin name and the function name.
+ */
+ public static final String FUNCTION_NAME_SEPARATOR = "-";
+
+ /**
+ * Form the full function name.
+ *
+ * @param pluginName The name of the plugin that the function is in.
+ * @param functionName The name of the function.
+ * @return The key for the function.
+ */
+ public static String formFullFunctionName(@Nullable String pluginName, String functionName) {
+ if (pluginName == null) {
+ pluginName = "";
+ }
+ return String.format("%s%s%s", pluginName, FUNCTION_NAME_SEPARATOR, functionName);
+ }
+
+ /**
+ * Check whether the given function is allowed.
+ *
+ * @param function The function to check.
+ * @return Whether the function is allowed.
+ */
+ public boolean isFunctionAllowed(KernelFunction> function) {
+ return isFunctionAllowed(function.getPluginName(), function.getName());
+ }
+
+ /**
+ * Check whether the given function is allowed.
+ *
+ * @param pluginName The name of the plugin that the function is in.
+ * @param functionName The name of the function.
+ * @return Whether the function is allowed.
+ */
+ public boolean isFunctionAllowed(@Nullable String pluginName, String functionName) {
+ // If no functions are provided, all functions are allowed.
+ if (functions == null || functions.isEmpty()) {
+ return true;
+ }
+
+ String key = formFullFunctionName(pluginName, functionName);
+ return fullFunctionNames.contains(key);
+ }
+}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/FunctionChoiceBehaviorOptions.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/FunctionChoiceBehaviorOptions.java
new file mode 100644
index 000000000..ffb17c780
--- /dev/null
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/FunctionChoiceBehaviorOptions.java
@@ -0,0 +1,50 @@
+// Copyright (c) Microsoft. All rights reserved.
+package com.microsoft.semantickernel.functionchoice;
+
+import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
+
+public class FunctionChoiceBehaviorOptions {
+ private final boolean parallelCallsAllowed;
+
+ private FunctionChoiceBehaviorOptions(boolean parallelCallsAllowed) {
+ this.parallelCallsAllowed = parallelCallsAllowed;
+ }
+
+ /**
+ * Returns a new builder for {@link FunctionChoiceBehaviorOptions}.
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Indicates whether parallel calls to functions are allowed.
+ *
+ * @return True if parallel calls are allowed; otherwise, false.
+ */
+ public boolean isParallelCallsAllowed() {
+ return parallelCallsAllowed;
+ }
+
+ /**
+ * Builder for {@link FunctionChoiceBehaviorOptions}.
+ */
+ public static class Builder implements SemanticKernelBuilder {
+ private boolean allowParallelCalls = false;
+
+ /**
+ * Sets whether parallel calls to functions are allowed.
+ *
+ * @param allowParallelCalls True if parallel calls are allowed; otherwise, false.
+ * @return The builder instance.
+ */
+ public Builder withParallelCallsAllowed(boolean allowParallelCalls) {
+ this.allowParallelCalls = allowParallelCalls;
+ return this;
+ }
+
+ public FunctionChoiceBehaviorOptions build() {
+ return new FunctionChoiceBehaviorOptions(allowParallelCalls);
+ }
+ }
+}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/NoneFunctionChoiceBehavior.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/NoneFunctionChoiceBehavior.java
new file mode 100644
index 000000000..f0d247d36
--- /dev/null
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/NoneFunctionChoiceBehavior.java
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft. All rights reserved.
+package com.microsoft.semantickernel.functionchoice;
+
+import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
+
+import javax.annotation.Nullable;
+import java.util.List;
+
+public class NoneFunctionChoiceBehavior extends FunctionChoiceBehavior {
+
+ /**
+ * Create a new instance of NoneFunctionChoiceBehavior.
+ */
+ public NoneFunctionChoiceBehavior(@Nullable List> functions,
+ @Nullable FunctionChoiceBehaviorOptions options) {
+ super(functions, options);
+ }
+}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/RequiredFunctionChoiceBehavior.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/RequiredFunctionChoiceBehavior.java
new file mode 100644
index 000000000..ac1ae2bfe
--- /dev/null
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/functionchoice/RequiredFunctionChoiceBehavior.java
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft. All rights reserved.
+package com.microsoft.semantickernel.functionchoice;
+
+import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
+
+import javax.annotation.Nullable;
+import java.util.List;
+
+public class RequiredFunctionChoiceBehavior extends AutoFunctionChoiceBehavior {
+
+ /**
+ * Create a new instance of RequiredFunctionChoiceBehavior.
+ *
+ * @param autoInvoke Whether auto-invocation is enabled.
+ * @param functions A set of functions to advertise to the model.
+ * @param options Options for the function choice behavior.
+ */
+ public RequiredFunctionChoiceBehavior(boolean autoInvoke,
+ @Nullable List> functions,
+ @Nullable FunctionChoiceBehaviorOptions options) {
+ super(autoInvoke, functions, options);
+ }
+}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokedEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokedEvent.java
index 8f2d7eed8..7a39cdfe8 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokedEvent.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokedEvent.java
@@ -3,7 +3,7 @@
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import javax.annotation.Nullable;
@@ -16,7 +16,7 @@ public class FunctionInvokedEvent implements KernelHookEvent {
private final KernelFunction function;
@Nullable
- private final KernelFunctionArguments arguments;
+ private final KernelArguments arguments;
private final FunctionResult result;
/**
@@ -28,10 +28,10 @@ public class FunctionInvokedEvent implements KernelHookEvent {
*/
public FunctionInvokedEvent(
KernelFunction function,
- @Nullable KernelFunctionArguments arguments,
+ @Nullable KernelArguments arguments,
FunctionResult result) {
this.function = function;
- this.arguments = KernelFunctionArguments.builder().withVariables(arguments).build();
+ this.arguments = KernelArguments.builder().withVariables(arguments).build();
this.result = result;
}
@@ -51,7 +51,7 @@ public KernelFunction getFunction() {
*/
@SuppressFBWarnings("EI_EXPOSE_REP")
@Nullable
- public KernelFunctionArguments getArguments() {
+ public KernelArguments getArguments() {
return arguments;
}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokingEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokingEvent.java
index ab765cabe..ca360a760 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokingEvent.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokingEvent.java
@@ -2,7 +2,7 @@
package com.microsoft.semantickernel.hooks;
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import javax.annotation.Nullable;
@@ -16,7 +16,7 @@
public class FunctionInvokingEvent implements KernelHookEvent {
private final KernelFunction function;
- private final KernelFunctionArguments arguments;
+ private final KernelArguments arguments;
/**
* Creates a new instance of the FunctionInvokingEvent class.
@@ -25,9 +25,9 @@ public class FunctionInvokingEvent implements KernelHookEvent {
* @param arguments The arguments that are being passed to the function
*/
public FunctionInvokingEvent(KernelFunction function,
- @Nullable KernelFunctionArguments arguments) {
+ @Nullable KernelArguments arguments) {
this.function = function;
- this.arguments = KernelFunctionArguments.builder().withVariables(arguments).build();
+ this.arguments = KernelArguments.builder().withVariables(arguments).build();
}
/**
@@ -45,7 +45,7 @@ public KernelFunction getFunction() {
* @return the arguments
*/
@SuppressFBWarnings("EI_EXPOSE_REP")
- public KernelFunctionArguments getArguments() {
+ public KernelArguments getArguments() {
return arguments;
}
}
\ No newline at end of file
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreToolCallEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreToolCallEvent.java
index c991efca1..42430f085 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreToolCallEvent.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreToolCallEvent.java
@@ -3,7 +3,7 @@
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import javax.annotation.Nullable;
@@ -15,7 +15,7 @@ public class PreToolCallEvent implements KernelHookEvent {
private final ContextVariableTypes contextVariableTypes;
private final String functionName;
@Nullable
- private final KernelFunctionArguments arguments;
+ private final KernelArguments arguments;
private final KernelFunction> function;
/**
@@ -29,7 +29,7 @@ public class PreToolCallEvent implements KernelHookEvent {
@SuppressFBWarnings("EI_EXPOSE_REP2")
public PreToolCallEvent(
String functionName,
- @Nullable KernelFunctionArguments arguments,
+ @Nullable KernelArguments arguments,
KernelFunction> function,
ContextVariableTypes contextVariableTypes) {
this.functionName = functionName;
@@ -44,7 +44,7 @@ public PreToolCallEvent(
*/
@SuppressFBWarnings("EI_EXPOSE_REP")
@Nullable
- public KernelFunctionArguments getArguments() {
+ public KernelArguments getArguments() {
return arguments;
}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderedEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderedEvent.java
index f3f349725..348d3bf12 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderedEvent.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderedEvent.java
@@ -2,7 +2,7 @@
package com.microsoft.semantickernel.hooks;
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import javax.annotation.Nullable;
@@ -12,7 +12,7 @@
public class PromptRenderedEvent implements KernelHookEvent {
private final KernelFunction> function;
- private final KernelFunctionArguments arguments;
+ private final KernelArguments arguments;
private final String prompt;
/**
@@ -24,10 +24,10 @@ public class PromptRenderedEvent implements KernelHookEvent {
*/
public PromptRenderedEvent(
KernelFunction function,
- @Nullable KernelFunctionArguments arguments,
+ @Nullable KernelArguments arguments,
String prompt) {
this.function = function;
- this.arguments = KernelFunctionArguments.builder().withVariables(arguments).build();
+ this.arguments = KernelArguments.builder().withVariables(arguments).build();
this.prompt = prompt;
}
@@ -46,7 +46,7 @@ public KernelFunction getFunction() {
* @return the arguments
*/
@SuppressFBWarnings("EI_EXPOSE_REP")
- public KernelFunctionArguments getArguments() {
+ public KernelArguments getArguments() {
return arguments;
}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderingEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderingEvent.java
index 7bba17a38..fe9c54459 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderingEvent.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderingEvent.java
@@ -2,7 +2,7 @@
package com.microsoft.semantickernel.hooks;
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import javax.annotation.Nullable;
@@ -12,7 +12,7 @@
public class PromptRenderingEvent implements KernelHookEvent {
private final KernelFunction> function;
- private final KernelFunctionArguments arguments;
+ private final KernelArguments arguments;
/**
* Creates a new instance of the {@link PromptRenderingEvent} class.
@@ -21,9 +21,9 @@ public class PromptRenderingEvent implements KernelHookEvent {
* @param arguments the arguments
*/
public PromptRenderingEvent(KernelFunction> function,
- @Nullable KernelFunctionArguments arguments) {
+ @Nullable KernelArguments arguments) {
this.function = function;
- this.arguments = KernelFunctionArguments.builder().withVariables(arguments).build();
+ this.arguments = KernelArguments.builder().withVariables(arguments).build();
}
/**
@@ -41,7 +41,7 @@ public KernelFunction> getFunction() {
* @return the arguments
*/
@SuppressFBWarnings("EI_EXPOSE_REP")
- public KernelFunctionArguments getArguments() {
+ public KernelArguments getArguments() {
return arguments;
}
}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/ChatCompletionSpan.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/ChatCompletionSpan.java
index 87945860a..9fa465ed9 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/ChatCompletionSpan.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/ChatCompletionSpan.java
@@ -104,8 +104,8 @@ public void endSpanWithUsage(ChatCompletions chatCompletions) {
CompletionsUsage usage = chatCompletions.getUsage();
getSpan().setStatus(StatusCode.OK);
getSpan()
- .setAttribute("gen_ai.response.completion_tokens", usage.getCompletionTokens());
- getSpan().setAttribute("gen_ai.response.prompt_tokens", usage.getPromptTokens());
+ .setAttribute("gen_ai.usage.output_tokens", usage.getCompletionTokens());
+ getSpan().setAttribute("gen_ai.usage.input_tokens", usage.getPromptTokens());
close();
}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/FunctionSpan.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/FunctionSpan.java
index 601b41305..72cc02609 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/FunctionSpan.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/telemetry/FunctionSpan.java
@@ -2,7 +2,7 @@
package com.microsoft.semantickernel.implementation.telemetry;
import com.microsoft.semantickernel.orchestration.FunctionResult;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.SpanKind;
@@ -27,7 +27,7 @@ public static FunctionSpan build(
ContextView contextView,
String pluginName,
String name,
- KernelFunctionArguments arguments) {
+ KernelArguments arguments) {
SpanBuilder builder = telemetry.spanBuilder(
String.format("function_invocation %s-%s", pluginName, name))
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/DefaultPromptTemplate.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/DefaultPromptTemplate.java
index d0b70083a..15b80a662 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/DefaultPromptTemplate.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/DefaultPromptTemplate.java
@@ -13,7 +13,7 @@
import com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks.VarBlock;
import com.microsoft.semantickernel.orchestration.InvocationContext;
import com.microsoft.semantickernel.semanticfunctions.InputVariable;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException;
@@ -137,7 +137,7 @@ private static PromptTemplateConfig addMissingInputVariables(
@Override
public Mono renderAsync(
Kernel kernel,
- @Nullable KernelFunctionArguments arguments,
+ @Nullable KernelArguments arguments,
@Nullable InvocationContext context) {
ContextVariableTypes types;
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeBlock.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeBlock.java
index e294c9251..cd6fffaad 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeBlock.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeBlock.java
@@ -9,7 +9,7 @@
import com.microsoft.semantickernel.localization.SemanticKernelResources;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.orchestration.InvocationContext;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import com.microsoft.semantickernel.semanticfunctions.KernelFunctionMetadata;
import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException;
import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException.ErrorCodes;
@@ -97,7 +97,7 @@ private boolean isValidFunctionCall() {
@Override
public Mono renderCodeAsync(
Kernel kernel,
- @Nullable KernelFunctionArguments arguments,
+ @Nullable KernelArguments arguments,
@Nullable InvocationContext context) {
if (!this.isValid()) {
throw new TemplateException(ErrorCodes.SYNTAX_ERROR);
@@ -136,7 +136,7 @@ public Mono renderCodeAsync(
private Mono> renderFunctionCallAsync(
FunctionIdBlock fBlock,
Kernel kernel,
- @Nullable KernelFunctionArguments arguments,
+ @Nullable KernelArguments arguments,
InvocationContext context,
ContextVariableType resultType) {
@@ -145,7 +145,7 @@ private Mono> renderFunctionCallAsync(
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,
- KernelFunctionArguments.builder().withVariables(arguments).build(),
+ KernelArguments.builder().withVariables(arguments).build(),
context);
}
@@ -168,10 +168,10 @@ private Mono> renderFunctionCallAsync(
/// The prompt rendering arguments.
/// The function arguments.
/// Occurs when any argument other than the first is not a named argument.
- private KernelFunctionArguments enrichFunctionArguments(
+ private KernelArguments enrichFunctionArguments(
Kernel kernel,
FunctionIdBlock fBlock,
- KernelFunctionArguments arguments,
+ KernelArguments arguments,
@Nullable InvocationContext context) {
Block firstArg = this.tokens.get(1);
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeRendering.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeRendering.java
index 7a411a095..673bcf68a 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeRendering.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/CodeRendering.java
@@ -3,7 +3,7 @@
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.orchestration.InvocationContext;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import javax.annotation.Nullable;
import reactor.core.publisher.Mono;
@@ -24,6 +24,6 @@ public interface CodeRendering {
*/
Mono renderCodeAsync(
Kernel kernel,
- @Nullable KernelFunctionArguments arguments,
+ @Nullable KernelArguments arguments,
@Nullable InvocationContext context);
}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/FunctionIdBlock.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/FunctionIdBlock.java
index 58f8f5346..69e5a63be 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/FunctionIdBlock.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/FunctionIdBlock.java
@@ -2,7 +2,7 @@
package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks;
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import javax.annotation.Nullable;
/**
@@ -49,7 +49,7 @@ private static boolean hasMoreThanOneDot(String value) {
@Override
@Nullable
- public String render(ContextVariableTypes types, @Nullable KernelFunctionArguments variables) {
+ public String render(ContextVariableTypes types, @Nullable KernelArguments variables) {
return this.getContent();
}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/NamedArgBlock.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/NamedArgBlock.java
index 010ba44e1..bed795020 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/NamedArgBlock.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/NamedArgBlock.java
@@ -7,7 +7,7 @@
import com.microsoft.semantickernel.exceptions.SKException;
import com.microsoft.semantickernel.implementation.Verify;
import com.microsoft.semantickernel.localization.SemanticKernelResources;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -132,7 +132,7 @@ public boolean isValid() {
}
@Override
- public String render(ContextVariableTypes types, @Nullable KernelFunctionArguments variables) {
+ public String render(ContextVariableTypes types, @Nullable KernelArguments variables) {
return getContent();
}
@@ -155,7 +155,7 @@ public String getName() {
}
@SuppressWarnings("NullAway")
- public String getValue(ContextVariableTypes types, KernelFunctionArguments arguments) {
+ public String getValue(ContextVariableTypes types, KernelArguments arguments) {
boolean valueIsValidValBlock = this.valBlock != null && this.valBlock.isValid();
if (valueIsValidValBlock) {
return this.valBlock.render(types, arguments);
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextBlock.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextBlock.java
index 3b7d1c09c..38128538e 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextBlock.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextBlock.java
@@ -2,7 +2,7 @@
package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks;
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import javax.annotation.Nullable;
public final class TextBlock extends Block implements TextRendering {
@@ -21,7 +21,7 @@ public boolean isValid() {
}
@Override
- public String render(ContextVariableTypes types, @Nullable KernelFunctionArguments variables) {
+ public String render(ContextVariableTypes types, @Nullable KernelArguments variables) {
return super.getContent();
}
}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextRendering.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextRendering.java
index 751190742..184b4ca45 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextRendering.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/TextRendering.java
@@ -2,7 +2,7 @@
package com.microsoft.semantickernel.implementation.templateengine.tokenizer.blocks;
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import javax.annotation.Nullable;
/**
@@ -17,5 +17,5 @@ public interface TextRendering {
* @return Rendered content
*/
@Nullable
- String render(ContextVariableTypes types, @Nullable KernelFunctionArguments variables);
+ String render(ContextVariableTypes types, @Nullable KernelArguments variables);
}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/ValBlock.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/ValBlock.java
index 3d647840f..d81c84b9a 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/ValBlock.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/ValBlock.java
@@ -3,7 +3,7 @@
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.localization.SemanticKernelResources;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.util.annotation.Nullable;
@@ -41,7 +41,7 @@ public static boolean hasValPrefix(@Nullable String text) {
@Override
@Nullable
- public String render(ContextVariableTypes types, @Nullable KernelFunctionArguments variables) {
+ public String render(ContextVariableTypes types, @Nullable KernelArguments variables) {
return value;
}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/VarBlock.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/VarBlock.java
index 1aec228c3..5ae70bb32 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/VarBlock.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/templateengine/tokenizer/blocks/VarBlock.java
@@ -4,7 +4,7 @@
import com.microsoft.semantickernel.contextvariables.ContextVariable;
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.localization.SemanticKernelResources;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import com.microsoft.semantickernel.templateengine.semantickernel.TemplateException;
import javax.annotation.Nullable;
import org.slf4j.Logger;
@@ -26,7 +26,7 @@ public VarBlock(String content) {
}
@Override
- public String render(ContextVariableTypes types, @Nullable KernelFunctionArguments variables) {
+ public String render(ContextVariableTypes types, @Nullable KernelArguments variables) {
if (variables == null) {
return "";
}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionInvocation.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionInvocation.java
index 435d8538f..9b8a518c3 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionInvocation.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionInvocation.java
@@ -8,13 +8,14 @@
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
import com.microsoft.semantickernel.contextvariables.converters.ContextVariableJacksonConverter;
import com.microsoft.semantickernel.exceptions.SKException;
+import com.microsoft.semantickernel.functionchoice.FunctionChoiceBehavior;
import com.microsoft.semantickernel.hooks.KernelHook;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.hooks.KernelHooks.UnmodifiableKernelHooks;
import com.microsoft.semantickernel.implementation.telemetry.SemanticKernelTelemetry;
import com.microsoft.semantickernel.localization.SemanticKernelResources;
import com.microsoft.semantickernel.semanticfunctions.KernelFunction;
-import com.microsoft.semantickernel.semanticfunctions.KernelFunctionArguments;
+import com.microsoft.semantickernel.semanticfunctions.KernelArguments;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.NoSuchElementException;
import java.util.function.BiConsumer;
@@ -41,13 +42,16 @@ public class FunctionInvocation extends Mono> {
protected final ContextVariableType resultType;
protected final ContextVariableTypes contextVariableTypes = new ContextVariableTypes();
@Nullable
- protected KernelFunctionArguments arguments;
+ protected KernelArguments arguments;
@Nullable
protected UnmodifiableKernelHooks hooks;
@Nullable
protected PromptExecutionSettings promptExecutionSettings;
@Nullable
protected ToolCallBehavior toolCallBehavior;
+ @Nullable
+ protected FunctionChoiceBehavior functionChoiceBehavior;
+
@Nullable
protected SemanticKernelTelemetry telemetry;
@@ -95,7 +99,7 @@ private static void performSubscribe(
CoreSubscriber super FunctionResult> coreSubscriber,
Kernel kernel,
KernelFunction> function,
- @Nullable KernelFunctionArguments arguments,
+ @Nullable KernelArguments arguments,
@Nullable ContextVariableType variableType,
@Nullable InvocationContext context) {
if (variableType == null) {
@@ -111,7 +115,7 @@ private static void performSubscribe(
function
.invokeAsync(
kernel,
- KernelFunctionArguments
+ KernelArguments
.builder()
.withVariables(arguments)
.build(),
@@ -174,9 +178,9 @@ private static UnmodifiableKernelHooks unmodifiableClone(
* @return this {@code FunctionInvocation} for fluent chaining.
*/
public FunctionInvocation withArguments(
- @Nullable KernelFunctionArguments arguments) {
+ @Nullable KernelArguments arguments) {
logSubscribeWarning();
- this.arguments = KernelFunctionArguments.builder().withVariables(arguments).build();
+ this.arguments = KernelArguments.builder().withVariables(arguments).build();
return this;
}
@@ -196,6 +200,7 @@ public FunctionInvocation withResultType(ContextVariableType resultTyp
.withArguments(arguments)
.addKernelHooks(hooks)
.withPromptExecutionSettings(promptExecutionSettings)
+ .withFunctionChoiceBehavior(functionChoiceBehavior)
.withToolCallBehavior(toolCallBehavior)
.withTypes(contextVariableTypes);
}
@@ -287,10 +292,32 @@ public FunctionInvocation withPromptExecutionSettings(
*/
public FunctionInvocation withToolCallBehavior(@Nullable ToolCallBehavior toolCallBehavior) {
logSubscribeWarning();
+ if (toolCallBehavior != null && functionChoiceBehavior != null) {
+ throw new SKException(
+ "ToolCallBehavior cannot be set when FunctionChoiceBehavior is set.");
+ }
this.toolCallBehavior = toolCallBehavior;
return this;
}
+ /**
+ * Supply function choice behavior to the function invocation.
+ *
+ * @param functionChoiceBehavior The function choice behavior to supply to the function
+ * invocation.
+ * @return this {@code FunctionInvocation} for fluent chaining.
+ */
+ public FunctionInvocation withFunctionChoiceBehavior(
+ @Nullable FunctionChoiceBehavior functionChoiceBehavior) {
+ if (functionChoiceBehavior != null && toolCallBehavior != null) {
+ throw new SKException(
+ "FunctionChoiceBehavior cannot be set when ToolCallBehavior is set.");
+ }
+ logSubscribeWarning();
+ this.functionChoiceBehavior = functionChoiceBehavior;
+ return this;
+ }
+
/**
* Supply a type converter to the function invocation.
*
@@ -340,6 +367,7 @@ public FunctionInvocation withInvocationContext(
}
logSubscribeWarning();
withTypes(invocationContext.getContextVariableTypes());
+ withFunctionChoiceBehavior(invocationContext.getFunctionChoiceBehavior());
withToolCallBehavior(invocationContext.getToolCallBehavior());
withPromptExecutionSettings(invocationContext.getPromptExecutionSettings());
addKernelHooks(invocationContext.getKernelHooks());
@@ -387,6 +415,7 @@ public void subscribe(CoreSubscriber super FunctionResult> coreSubscriber)
hooks,
promptExecutionSettings,
toolCallBehavior,
+ functionChoiceBehavior,
contextVariableTypes,
InvocationReturnMode.NEW_MESSAGES_ONLY,
telemetry));
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/InvocationContext.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/InvocationContext.java
index 6fd3f0d21..6a8547c43 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/InvocationContext.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/InvocationContext.java
@@ -4,6 +4,8 @@
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter;
import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
+import com.microsoft.semantickernel.exceptions.SKException;
+import com.microsoft.semantickernel.functionchoice.FunctionChoiceBehavior;
import com.microsoft.semantickernel.hooks.KernelHooks;
import com.microsoft.semantickernel.hooks.KernelHooks.UnmodifiableKernelHooks;
import com.microsoft.semantickernel.implementation.telemetry.SemanticKernelTelemetry;
@@ -23,6 +25,8 @@ public class InvocationContext {
private final PromptExecutionSettings promptExecutionSettings;
@Nullable
private final ToolCallBehavior toolCallBehavior;
+ @Nullable
+ private final FunctionChoiceBehavior functionChoiceBehavior;
private final ContextVariableTypes contextVariableTypes;
private final InvocationReturnMode invocationReturnMode;
private final SemanticKernelTelemetry telemetry;
@@ -39,12 +43,14 @@ protected InvocationContext(
@Nullable KernelHooks hooks,
@Nullable PromptExecutionSettings promptExecutionSettings,
@Nullable ToolCallBehavior toolCallBehavior,
+ @Nullable FunctionChoiceBehavior functionChoiceBehavior,
@Nullable ContextVariableTypes contextVariableTypes,
InvocationReturnMode invocationReturnMode,
SemanticKernelTelemetry telemetry) {
this.hooks = unmodifiableClone(hooks);
this.promptExecutionSettings = promptExecutionSettings;
this.toolCallBehavior = toolCallBehavior;
+ this.functionChoiceBehavior = functionChoiceBehavior;
this.invocationReturnMode = invocationReturnMode;
if (contextVariableTypes == null) {
this.contextVariableTypes = new ContextVariableTypes();
@@ -61,6 +67,7 @@ protected InvocationContext() {
this.hooks = null;
this.promptExecutionSettings = null;
this.toolCallBehavior = null;
+ this.functionChoiceBehavior = null;
this.contextVariableTypes = new ContextVariableTypes();
this.invocationReturnMode = InvocationReturnMode.NEW_MESSAGES_ONLY;
this.telemetry = null;
@@ -76,6 +83,7 @@ protected InvocationContext(@Nullable InvocationContext context) {
this.hooks = null;
this.promptExecutionSettings = null;
this.toolCallBehavior = null;
+ this.functionChoiceBehavior = null;
this.contextVariableTypes = new ContextVariableTypes();
this.invocationReturnMode = InvocationReturnMode.NEW_MESSAGES_ONLY;
this.telemetry = null;
@@ -83,6 +91,7 @@ protected InvocationContext(@Nullable InvocationContext context) {
this.hooks = context.hooks;
this.promptExecutionSettings = context.promptExecutionSettings;
this.toolCallBehavior = context.toolCallBehavior;
+ this.functionChoiceBehavior = context.functionChoiceBehavior;
this.contextVariableTypes = context.contextVariableTypes;
this.invocationReturnMode = context.invocationReturnMode;
this.telemetry = context.telemetry;
@@ -156,6 +165,16 @@ public ToolCallBehavior getToolCallBehavior() {
return toolCallBehavior;
}
+ /**
+ * Get the behavior for function choice.
+ *
+ * @return The behavior for function choice.
+ */
+ @Nullable
+ public FunctionChoiceBehavior getFunctionChoiceBehavior() {
+ return functionChoiceBehavior;
+ }
+
/**
* Get the types of context variables.
*
@@ -190,6 +209,8 @@ public static class Builder implements SemanticKernelBuilder
private PromptExecutionSettings promptExecutionSettings;
@Nullable
private ToolCallBehavior toolCallBehavior;
+ @Nullable
+ private FunctionChoiceBehavior functionChoiceBehavior;
private InvocationReturnMode invocationReturnMode = InvocationReturnMode.NEW_MESSAGES_ONLY;
@Nullable
private SemanticKernelTelemetry telemetry;
@@ -226,10 +247,30 @@ public Builder withPromptExecutionSettings(
*/
public Builder withToolCallBehavior(
@Nullable ToolCallBehavior toolCallBehavior) {
+ if (toolCallBehavior != null && functionChoiceBehavior != null) {
+ throw new SKException(
+ "ToolCallBehavior cannot be set when FunctionChoiceBehavior is set.");
+ }
this.toolCallBehavior = toolCallBehavior;
return this;
}
+ /**
+ * Add function choice behavior to the builder.
+ *
+ * @param functionChoiceBehavior the behavior to add.
+ * @return this {@link Builder}
+ */
+ public Builder withFunctionChoiceBehavior(
+ @Nullable FunctionChoiceBehavior functionChoiceBehavior) {
+ if (functionChoiceBehavior != null && toolCallBehavior != null) {
+ throw new SKException(
+ "FunctionChoiceBehavior cannot be set when ToolCallBehavior is set.");
+ }
+ this.functionChoiceBehavior = functionChoiceBehavior;
+ return this;
+ }
+
/**
* Add a context variable type converter to the builder.
*
@@ -269,7 +310,7 @@ public Builder withReturnMode(InvocationReturnMode invocationReturnMode) {
/**
* Add a tracer to the builder.
*
- * @param tracer the tracer to add.
+ * @param telemetry the tracer to add.
* @return this {@link Builder}
*/
public Builder withTelemetry(@Nullable SemanticKernelTelemetry telemetry) {
@@ -283,6 +324,7 @@ public InvocationContext build() {
telemetry = new SemanticKernelTelemetry();
}
return new InvocationContext(hooks, promptExecutionSettings, toolCallBehavior,
+ functionChoiceBehavior,
contextVariableTypes, invocationReturnMode, telemetry);
}
}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java
new file mode 100644
index 000000000..bf9e65658
--- /dev/null
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelArguments.java
@@ -0,0 +1,427 @@
+// Copyright (c) Microsoft. All rights reserved.
+package com.microsoft.semantickernel.semanticfunctions;
+
+import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
+import com.microsoft.semantickernel.contextvariables.CaseInsensitiveMap;
+import com.microsoft.semantickernel.contextvariables.ContextVariable;
+import com.microsoft.semantickernel.contextvariables.ContextVariableType;
+import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter;
+import com.microsoft.semantickernel.contextvariables.ContextVariableTypes;
+import com.microsoft.semantickernel.exceptions.SKException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.microsoft.semantickernel.orchestration.PromptExecutionSettings;
+import reactor.util.annotation.NonNull;
+
+/**
+ * Arguments to a kernel function.
+ */
+public class KernelArguments implements Map> {
+
+ /**
+ * Default key for the main input.
+ */
+ public static final String MAIN_KEY = "input";
+
+ protected final CaseInsensitiveMap> variables;
+ protected final Map executionSettings;
+
+ /**
+ * Create a new instance of KernelArguments.
+ *
+ * @param variables The variables to use for the function invocation.
+ */
+ protected KernelArguments(
+ @Nullable Map> variables,
+ @Nullable Map 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);
+ }
+ }
+
+ /**
+ * Create a new instance of KernelArguments.
+ *
+ * @param content The content to use for the function invocation.
+ */
+ protected KernelArguments(@NonNull ContextVariable> content) {
+ this();
+ this.variables.put(MAIN_KEY, content);
+ }
+
+ /**
+ * Create a new instance of KernelArguments.
+ */
+ protected KernelArguments() {
+ this.variables = new CaseInsensitiveMap<>();
+ this.executionSettings = new HashMap<>();
+ }
+
+ /**
+ * Create a new instance of KernelArguments.
+ *
+ * @param arguments The arguments to copy.
+ */
+ protected KernelArguments(@NonNull KernelArguments arguments) {
+ this.variables = new CaseInsensitiveMap<>(arguments.variables);
+ this.executionSettings = new HashMap<>(arguments.executionSettings);
+ }
+
+ /**
+ * Get the prompt execution settings
+ *
+ * @return prompt execution settings
+ */
+ @Nonnull
+ public Map getExecutionSettings() {
+ return Collections.unmodifiableMap(executionSettings);
+ }
+
+ /**
+ * 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().toPromptString(ContextVariableTypes.getGlobalTypes()),
+ (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
+ ContextVariable get(String key, Class clazz) {
+ ContextVariable> value = variables.get(key);
+ if (value == null) {
+ return null;
+ } else if (clazz.isAssignableFrom(value.getType().getClazz())) {
+ return (ContextVariable) value;
+ }
+
+ throw new SKException(
+ String.format(
+ "Variable %s is of type %s, but requested type is %s",
+ key, value.getType().getClazz(), clazz));
+ }
+
+ /**
+ * Return whether the variable with the given name is {@code null} or empty.
+ *
+ * @param key the key for the variable
+ * @return {@code true} if the variable is {@code null} or empty, {@code false} otherwise
+ */
+ 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
+ @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 keySet() {
+ return variables.keySet();
+ }
+
+ @Override
+ public Collection> values() {
+ return variables.values();
+ }
+
+ @Override
+ public Set>> entrySet() {
+ return variables.entrySet();
+ }
+
+ /**
+ * Create a copy of the current instance
+ *
+ * @return copy of the current instance
+ */
+ public KernelArguments copy() {
+ return new KernelArguments(variables, executionSettings);
+ }
+
+ /**
+ * Create a new instance of Builder.
+ *
+ * @return Builder
+ */
+ public static Builder> builder() {
+ return new Builder<>(KernelArguments::new);
+ }
+
+ /**
+ * Builder for ContextVariables
+ */
+ public static class Builder implements SemanticKernelBuilder {
+
+ private final Function constructor;
+ private final Map> variables;
+ private final Map executionSettings;
+
+ protected Builder(Function constructor) {
+ this.constructor = constructor;
+ this.variables = new HashMap<>();
+ this.executionSettings = new HashMap<>();
+ }
+
+ /**
+ * Builds an instance with the given content in the default main key
+ *
+ * @param content Entry to place in the "input" slot
+ * @param Type of the value
+ * @return {$code this} Builder for fluent coding
+ */
+ public Builder withInput(ContextVariable 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.ofGlobalType(content));
+ }
+
+ /**
+ * Builds an instance with the given content in the default main key
+ *
+ * @param content Entry to place in the "input" slot
+ * @param typeConverter Type converter for the content
+ * @param Type of the value
+ * @return {$code this} Builder for fluent coding
+ * @throws SKException if the content cannot be converted to a ContextVariable
+ */
+ public Builder withInput(T content, ContextVariableTypeConverter typeConverter) {
+ return withInput(new ContextVariable<>(
+ new ContextVariableType<>(
+ typeConverter,
+ typeConverter.getType()),
+ content));
+ }
+
+ /**
+ * Builds an instance with the given variables
+ *
+ * @param map Existing variables
+ * @return {$code this} Builder for fluent coding
+ */
+ public Builder withVariables(@Nullable Map> map) {
+ if (map == null) {
+ return this;
+ }
+ variables.putAll(map);
+ return this;
+ }
+
+ /**
+ * Set variable
+ *
+ * @param key variable name
+ * @param value variable value
+ * @param Type of the value
+ * @return {$code this} Builder for fluent coding
+ */
+ public Builder withVariable(String key, ContextVariable value) {
+ variables.put(key, value);
+ return this;
+ }
+
+ /**
+ * Set variable, uses the default type converters
+ *
+ * @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) {
+ if (value instanceof ContextVariable) {
+ return withVariable(key, (ContextVariable>) value);
+ }
+ return withVariable(key, ContextVariable.ofGlobalType(value));
+ }
+
+ /**
+ * Set variable
+ *
+ * @param key variable name
+ * @param value variable value
+ * @param typeConverter Type converter for the value
+ * @param Type of the value
+ * @return {$code this} Builder for fluent coding
+ * @throws SKException if the value cannot be converted to a ContextVariable
+ */
+ public Builder withVariable(String key, T value,
+ ContextVariableTypeConverter typeConverter) {
+ return withVariable(key, new ContextVariable<>(
+ new ContextVariableType<>(
+ typeConverter,
+ typeConverter.getType()),
+ value));
+ }
+
+ /**
+ * Set prompt execution settings
+ *
+ * @param executionSettings Execution settings
+ * @return {$code this} Builder for fluent coding
+ */
+ public Builder withExecutionSettings(PromptExecutionSettings executionSettings) {
+ return withExecutionSettings(Collections.singletonList(executionSettings));
+ }
+
+ /**
+ * Set prompt execution settings
+ *
+ * @param executionSettings Execution settings
+ * @return {$code this} Builder for fluent coding
+ */
+ public Builder withExecutionSettings(
+ Map executionSettings) {
+ if (executionSettings == null) {
+ return this;
+ }
+
+ this.executionSettings.putAll(executionSettings);
+ return this;
+ }
+
+ /**
+ * Set prompt execution settings
+ *
+ * @param executionSettings Execution settings
+ * @return {$code this} Builder for fluent coding
+ */
+ public Builder withExecutionSettings(List executionSettings) {
+ if (executionSettings == null) {
+ return this;
+ }
+
+ for (PromptExecutionSettings settings : executionSettings) {
+ String serviceId = settings.getServiceId();
+
+ if (this.executionSettings.containsKey(serviceId)) {
+ if (serviceId.equals(PromptExecutionSettings.DEFAULT_SERVICE_ID)) {
+ throw new SKException(
+ String.format(
+ "Multiple prompt execution settings with the default service id '%s' or no service id have been provided. Specify a single default prompt execution settings and provide a unique service id for all other instances.",
+ PromptExecutionSettings.DEFAULT_SERVICE_ID));
+ }
+
+ throw new SKException(
+ String.format(
+ "Multiple prompt execution settings with the service id '%s' have been provided. Specify a unique service id for all instances.",
+ serviceId));
+ }
+
+ this.executionSettings.put(serviceId, settings);
+ }
+
+ return this;
+ }
+
+ @Override
+ public U build() {
+ KernelArguments arguments = new KernelArguments(variables, executionSettings);
+ return constructor.apply(arguments);
+ }
+ }
+}
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunction.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunction.java
index 70f33bd75..742e84572 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunction.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunction.java
@@ -189,7 +189,7 @@ public KernelFunctionMetadata> getMetadata() {
*/
public abstract Mono> invokeAsync(
Kernel kernel,
- @Nullable KernelFunctionArguments arguments,
+ @Nullable KernelArguments arguments,
@Nullable ContextVariableType variableType,
@Nullable InvocationContext invocationContext);
@@ -221,7 +221,7 @@ public abstract Mono> invokeAsync(
*/
public FunctionResult invoke(
Kernel kernel,
- @Nullable KernelFunctionArguments arguments,
+ @Nullable KernelArguments arguments,
@Nullable ContextVariableType variableType,
@Nullable InvocationContext invocationContext) {
return invokeAsync(kernel, arguments, variableType, invocationContext).block();
diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionArguments.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionArguments.java
index f3b46c21a..76936cf23 100644
--- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionArguments.java
+++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/KernelFunctionArguments.java
@@ -17,16 +17,17 @@
/**
* Arguments to a kernel function.
+ *
+ * @deprecated Use {@link KernelArguments} instead.
*/
-public class KernelFunctionArguments implements Map> {
+@Deprecated
+public class KernelFunctionArguments extends KernelArguments {
/**
* Default key for the main input.
*/
public static final String MAIN_KEY = "input";
- private final CaseInsensitiveMap> variables;
-
/**
* Create a new instance of KernelFunctionArguments.
*
@@ -34,11 +35,7 @@ public class KernelFunctionArguments implements Map>
*/
protected KernelFunctionArguments(
@Nullable Map> variables) {
- if (variables == null) {
- this.variables = new CaseInsensitiveMap<>();
- } else {
- this.variables = new CaseInsensitiveMap<>(variables);
- }
+ super(variables, null);
}
/**
@@ -47,15 +44,23 @@ protected KernelFunctionArguments(
* @param content The content to use for the function invocation.
*/
protected KernelFunctionArguments(@NonNull ContextVariable> content) {
- this.variables = new CaseInsensitiveMap<>();
- this.variables.put(MAIN_KEY, content);
+ super(content);
+ }
+
+ /**
+ * Create a new instance of KernelArguments.
+ *
+ * @param arguments The arguments to copy.
+ */
+ protected KernelFunctionArguments(@NonNull KernelArguments arguments) {
+ super(arguments);
}
/**
* Create a new instance of KernelFunctionArguments.
*/
protected KernelFunctionArguments() {
- this.variables = new CaseInsensitiveMap<>();
+ super();
}
/**
@@ -208,121 +213,18 @@ public KernelFunctionArguments copy() {
/**
* Builder for ContextVariables
+ *
+ * @deprecated Use {@link KernelArguments} builder instead.
*/
- public static class Builder implements SemanticKernelBuilder {
-
- private final Map> variables;
+ @Deprecated
+ public static class Builder extends KernelArguments.Builder {
/**
* Create a new instance of Builder.
*/
+ @Deprecated
public Builder() {
- variables = new HashMap<>();
- }
-
- /**
- * Builds an instance with the given content in the default main key
- *
- * @param content Entry to place in the "input" slot
- * @param Type of the value
- * @return {$code this} Builder for fluent coding
- */
- public Builder withInput(ContextVariable 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.ofGlobalType(content));
- }
-
- /**
- * Builds an instance with the given content in the default main key
- *
- * @param content Entry to place in the "input" slot
- * @param typeConverter Type converter for the content
- * @param Type of the value
- * @return {$code this} Builder for fluent coding
- * @throws SKException if the content cannot be converted to a ContextVariable
- */
- public Builder withInput(T content, ContextVariableTypeConverter typeConverter) {
- return withInput(new ContextVariable<>(
- new ContextVariableType<>(
- typeConverter,
- typeConverter.getType()),
- content));
- }
-
- /**
- * Builds an instance with the given variables
- *
- * @param map Existing variables
- * @return {$code this} Builder for fluent coding
- */
- public Builder withVariables(@Nullable Map> map) {
- if (map == null) {
- return this;
- }
- variables.putAll(map);
- return this;
- }
-
- /**
- * Set variable
- *
- * @param key variable name
- * @param value variable value
- * @param Type of the value
- * @return {$code this} Builder for fluent coding
- */
- public Builder withVariable(String key, ContextVariable value) {
- variables.put(key, value);
- return this;
- }
-
- /**
- * Set variable, uses the default type converters
- *
- * @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) {
- if (value instanceof ContextVariable) {
- return withVariable(key, (ContextVariable>) value);
- }
- return withVariable(key, ContextVariable.ofGlobalType(value));
- }
-
- /**
- * Set variable
- *
- * @param key variable name
- * @param value variable value
- * @param typeConverter Type converter for the value
- * @param Type of the value
- * @return {$code this} Builder for fluent coding
- * @throws SKException if the value cannot be converted to a ContextVariable
- */
- public Builder withVariable(String key, T value,
- ContextVariableTypeConverter