Java: Add Java v1 core draft (#3969)

### Motivation and Context

<!-- Thank you for your contribution to the semantic-kernel repo!
Please help reviewers and future users, providing the following
information:
  1. Why is this change required?
  2. What problem does it solve?
  3. What scenario does it contribute to?
  4. If it fixes an open issue, please link to the issue here.
-->

### Description

<!-- Describe your changes, the overall approach, the underlying design.
These notes will help understanding how your code works. Thanks! -->

### Contribution Checklist

<!-- Before submitting this PR, please make sure: -->

- [ ] The code builds clean without any errors or warnings
- [ ] The PR follows the [SK Contribution
Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md)
and the [pre-submission formatting
script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts)
raises no violations
- [ ] All unit tests pass, and I have added new tests where possible
- [ ] I didn't break anyone 😄

---------

Co-authored-by: David Grieve <[email protected]>
This commit is contained in:
Milder Hernandez
2023-12-05 15:06:00 -05:00
committed by GitHub
co-authored by David Grieve
parent 4b92bf679e
commit 8f0aae4b14
45 changed files with 1119 additions and 414 deletions
@@ -184,6 +184,11 @@ public class OpenAIChatCompletion extends ClientBase implements ChatCompletion<O
return internalCreateNewChat(instructions);
}
@Override
public OpenAIChatHistory createNewChat() {
return internalCreateNewChat(null);
}
@Override
public Flux<String> generateMessageStream(
OpenAIChatHistory chat, @Nullable ChatRequestSettings requestSettings) {
@@ -237,11 +242,10 @@ public class OpenAIChatCompletion extends ClientBase implements ChatCompletion<O
* @return Chat object
*/
private static OpenAIChatHistory internalCreateNewChat(@Nullable String instructions) {
if (instructions == null) {
instructions = "";
OpenAIChatHistory history = new OpenAIChatHistory(instructions);
if (instructions != null && !instructions.isEmpty()) {
history.addUserMessage(instructions);
}
OpenAIChatHistory history = new OpenAIChatHistory("Assistant is a large language model.");
history.addUserMessage(instructions);
return history;
}
}
@@ -30,7 +30,7 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/** Standard Semantic Kernel callable plan. Plan is used to create trees of SKFunctions. */
public class Plan extends AbstractSkFunction<CompletionRequestSettings> {
public class Plan extends AbstractSkFunction {
private static final Pattern s_variablesRegex = Pattern.compile("\\$(\\w+)", Pattern.MULTILINE);
@@ -48,7 +48,7 @@ public class Plan extends AbstractSkFunction<CompletionRequestSettings> {
// Outputs for the plan, used to pass information to the caller
private List<String> outputs = new ArrayList<>();
@Nullable private SKFunction<?> function = null;
@Nullable private SKFunction function = null;
public Plan(
String goal,
@@ -69,7 +69,7 @@ public class Plan extends AbstractSkFunction<CompletionRequestSettings> {
}
public Plan(
SKFunction<?> function,
SKFunction function,
ContextVariables state,
List<String> functionOutputs,
KernelSkillsSupplier kernelSkillsSupplier) {
@@ -88,7 +88,7 @@ public class Plan extends AbstractSkFunction<CompletionRequestSettings> {
}
public Plan(
SKFunction<?> function,
SKFunction function,
@Nullable ContextVariables parameters,
ContextVariables state,
List<String> functionOutputs,
@@ -111,13 +111,13 @@ public class Plan extends AbstractSkFunction<CompletionRequestSettings> {
}
public Plan(
SKFunction<?> function,
SKFunction function,
List<String> functionOutputs,
KernelSkillsSupplier kernelSkillsSupplier) {
this(function, SKBuilders.variables().build(), functionOutputs, kernelSkillsSupplier);
}
public Plan(SKFunction<?> function, KernelSkillsSupplier kernelSkillsSupplier) {
public Plan(SKFunction function, KernelSkillsSupplier kernelSkillsSupplier) {
this(function, SKBuilders.variables().build(), new ArrayList<>(), kernelSkillsSupplier);
}
@@ -125,12 +125,12 @@ public class Plan extends AbstractSkFunction<CompletionRequestSettings> {
String goal,
ContextVariables parameters,
KernelSkillsSupplier kernelSkillsSupplier,
SKFunction<?>... steps) {
SKFunction... steps) {
this(goal, parameters, kernelSkillsSupplier);
this.addSteps(steps);
}
public Plan(String goal, KernelSkillsSupplier kernelSkillsSupplier, SKFunction<?>... steps) {
public Plan(String goal, KernelSkillsSupplier kernelSkillsSupplier, SKFunction... steps) {
this(goal, kernelSkillsSupplier);
this.addSteps(steps);
}
@@ -176,7 +176,7 @@ public class Plan extends AbstractSkFunction<CompletionRequestSettings> {
*
* @param steps The steps to add to the current plan.
*/
public void addSteps(SKFunction<?>... steps) {
public void addSteps(SKFunction... steps) {
List<Plan> plans =
Arrays.stream(steps)
.map(step -> new Plan(step, getSkillsSupplier()))
@@ -47,8 +47,7 @@ public class DefaultSequentialPlannerSKContext {
config = new SequentialPlannerRequestSettings();
}
Mono<SortedSet<SKFunction<?>>> functions =
getAvailableFunctionsAsync(config, semanticQuery);
Mono<SortedSet<SKFunction>> functions = getAvailableFunctionsAsync(config, semanticQuery);
return functions.map(
funcs ->
@@ -67,7 +66,7 @@ public class DefaultSequentialPlannerSKContext {
// functions</param>
/// <returns>A list of functions that are available to the user based on the semantic query and
// the excluded skills and functions.</returns>
public Mono<SortedSet<SKFunction<?>>> getAvailableFunctionsAsync(
public Mono<SortedSet<SKFunction>> getAvailableFunctionsAsync(
SequentialPlannerRequestSettings config, @Nullable String semanticQuery) {
Set<String> excludedSkills = config.getExcludedSkills();
Set<String> excludedFunctions = config.getExcludedFunctions();
@@ -76,14 +75,14 @@ public class DefaultSequentialPlannerSKContext {
// context.ThrowIfSkillCollectionNotSet();
ReadOnlySkillCollection skills = delegate.getSkills();
List<SKFunction<?>> functions;
List<SKFunction> functions;
if (skills != null) {
functions = skills.getAllFunctions().getAll();
} else {
functions = Collections.emptyList();
}
List<SKFunction<?>> availableFunctions =
List<SKFunction> availableFunctions =
functions.stream()
/*
// Is there any function that should be excluded?
@@ -99,8 +98,8 @@ public class DefaultSequentialPlannerSKContext {
&& !excludedFunctions.contains(s.getName()))
.collect(Collectors.toList());
Comparator<SKFunction<?>> comparator =
Comparator.<SKFunction<?>, String>comparing(SKFunction::getSkillName)
Comparator<SKFunction> comparator =
Comparator.<SKFunction, String>comparing(SKFunction::getSkillName)
.thenComparing(SKFunction::getName);
if (semanticQuery == null
@@ -110,7 +109,7 @@ public class DefaultSequentialPlannerSKContext {
|| config.getRelevancyThreshold() == null) {
// If no semantic query is provided, return all available functions.
// If a Memory provider has not been registered, return all available functions.
TreeSet<SKFunction<?>> result = new TreeSet<>(comparator);
TreeSet<SKFunction> result = new TreeSet<>(comparator);
result.addAll(availableFunctions);
return Mono.just(result);
} else {
@@ -121,7 +120,7 @@ public class DefaultSequentialPlannerSKContext {
SemanticTextMemory updatedMemory =
updatedContext.getSemanticMemory();
if (updatedMemory == null) {
return Mono.just(new ArrayList<SKFunction<Void>>());
return Mono.just(new ArrayList<SKFunction>());
}
// Search for functions that match the semantic query.
return updatedMemory
@@ -143,26 +142,26 @@ public class DefaultSequentialPlannerSKContext {
.map(SKFunction::getName)
.collect(Collectors.toList());
List<SKFunction<?>> missingFunctions =
List<SKFunction> missingFunctions =
getMissingFunctions(
includedFunctions, availableFunctions, added);
ArrayList<SKFunction<?>> res = new ArrayList<>(memories);
ArrayList<SKFunction> res = new ArrayList<>(memories);
res.addAll(missingFunctions);
return res;
})
.map(
res -> {
TreeSet<SKFunction<?>> result = new TreeSet<>(comparator);
TreeSet<SKFunction> result = new TreeSet<>(comparator);
result.addAll(availableFunctions);
return result;
});
}
}
private static List<SKFunction<?>> getMissingFunctions(
private static List<SKFunction> getMissingFunctions(
Set<String> includedFunctions,
List<SKFunction<?>> availableFunctions,
List<SKFunction> availableFunctions,
List<String> added) {
return includedFunctions.stream()
.filter(func -> !added.contains(func))
@@ -173,8 +172,8 @@ public class DefaultSequentialPlannerSKContext {
.collect(Collectors.toList());
}
public Mono<? extends List<? extends SKFunction<?>>> getRelevantFunctionsAsync(
List<SKFunction<?>> availableFunctions, List<MemoryQueryResult> memories) {
public Mono<? extends List<? extends SKFunction>> getRelevantFunctionsAsync(
List<SKFunction> availableFunctions, List<MemoryQueryResult> memories) {
return Flux.fromIterable(memories)
.map(
memoryEntry ->
@@ -195,7 +194,7 @@ public class DefaultSequentialPlannerSKContext {
/// </summary>
/// <param name="context">The SKContext to save the functions to.</param>
/// <param name="availableFunctions">The available functions to save.</param>
Mono<SKContext> rememberFunctionsAsync(List<SKFunction<?>> availableFunctions) {
Mono<SKContext> rememberFunctionsAsync(List<SKFunction> availableFunctions) {
// Check if the functions have already been saved to memory.
if (delegate.getVariables().asMap().containsKey(PlanSKFunctionsAreRemembered)) {
return Mono.just(delegate);
@@ -20,7 +20,6 @@ import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
import com.microsoft.semantickernel.skilldefinition.annotations.DefineSKFunction;
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionParameters;
import com.microsoft.semantickernel.textcompletion.CompletionRequestSettings;
import com.microsoft.semantickernel.util.EmbeddedResourceLoader;
import java.io.FileNotFoundException;
import java.util.ArrayList;
@@ -94,7 +93,7 @@ public class DefaultStepwisePlanner implements StepwisePlanner {
private final Kernel kernel;
private final StepwisePlannerConfig config;
private final SKFunction<?> systemStepFunction;
private final SKFunction systemStepFunction;
private final SKContext context;
private final ReadOnlyFunctionCollection nativeFunctions;
@@ -189,7 +188,7 @@ public class DefaultStepwisePlanner implements StepwisePlanner {
String functionDescriptions = this.getFunctionDescriptions();
SKFunction<?> planStep = nativeFunctions.getFunction("ExecutePlan", SKFunction.class);
SKFunction planStep = nativeFunctions.getFunction("ExecutePlan", SKFunction.class);
ContextVariables parameters =
SKBuilders.variables()
@@ -527,8 +526,8 @@ public class DefaultStepwisePlanner implements StepwisePlanner {
}
private Mono<String> invokeActionAsync(String actionName, Map<String, String> actionVariables) {
List<SKFunction<?>> availableFunctions = this.getAvailableFunctions();
Optional<SKFunction<?>> targetFunction =
List<SKFunction> availableFunctions = this.getAvailableFunctions();
Optional<SKFunction> targetFunction =
availableFunctions.stream()
.filter(
f -> {
@@ -548,7 +547,7 @@ public class DefaultStepwisePlanner implements StepwisePlanner {
ErrorCodes.UNKNOWN_ERROR, "The function '" + actionName + "' was not found.");
}
SKFunction<?> function =
SKFunction function =
kernel.getFunction(
targetFunction.get().getSkillName(), targetFunction.get().getName());
@@ -575,7 +574,7 @@ public class DefaultStepwisePlanner implements StepwisePlanner {
return actionContext;
}
private List<SKFunction<?>> getAvailableFunctions() {
private List<SKFunction> getAvailableFunctions() {
return this.context.getSkills().getAllFunctions().getAll().stream()
.filter(
fun ->
@@ -585,22 +584,21 @@ public class DefaultStepwisePlanner implements StepwisePlanner {
.contains(fun.getName()))
.sorted(
(a, b) ->
Comparator.<SKFunction<?>, String>comparing(
SKFunction::getSkillName)
Comparator.<SKFunction, String>comparing(SKFunction::getSkillName)
.thenComparing(SKFunction::getName)
.compare(a, b))
.collect(Collectors.toList());
}
private String getFunctionDescriptions() {
List<SKFunction<?>> availableFunctions = this.getAvailableFunctions();
List<SKFunction> availableFunctions = this.getAvailableFunctions();
return availableFunctions.stream()
.map(x -> toManualString(Objects.requireNonNull(x.describe())))
.collect(Collectors.joining("\n"));
}
private SKFunction<CompletionRequestSettings> importStepwiseFunction(
private SKFunction importStepwiseFunction(
Kernel kernel, String promptTemplate, PromptTemplateConfig config) {
PromptTemplate template =
SKBuilders.promptTemplate()
@@ -183,9 +183,10 @@ public class TextMemorySkill {
new MemoryException(MemoryException.ErrorCodes.UNKNOWN, "Memory not present"));
}
// TODO: 1.0 fix cast
// Validate parameters
if (collection == null || collection.trim().isEmpty()) {
collection = context.getVariables().get(TextMemorySkill.COLLECTION_PARAM);
collection = (String) context.getVariables().get(TextMemorySkill.COLLECTION_PARAM);
if (collection == null) collection = DEFAULT_COLLECTION;
}
final String _collection = collection;
+16 -16
View File
@@ -64,22 +64,22 @@
</properties>
<modules>
<!-- <module>connectors/semantickernel-connectors-ai-openai</module>
<module>connectors/semantickernel-connectors-memory-sqlite</module>
<module>connectors/semantickernel-connectors-ai-openai</module>
<!-- <module>connectors/semantickernel-connectors-memory-sqlite</module>-->
<module>connectors/semantickernel-connectors-memory-azurecognitivesearch</module>
<module>connectors/semantickernel-connectors-memory-jdbc</module>
<module>connectors/semantickernel-connectors-memory-postgresql</module>
<module>connectors/semantickernel-connectors-memory-mysql</module> -->
<!-- <module>connectors/semantickernel-connectors-memory-jdbc</module>-->
<!-- <module>connectors/semantickernel-connectors-memory-postgresql</module>-->
<!-- <module>connectors/semantickernel-connectors-memory-mysql</module>-->
<!-- <module>extensions/semantickernel-planners</module>
<!-- <module>extensions/semantickernel-planners</module>-->
<module>extensions/semantickernel-gpt3-tokenizer</module>
<module>extensions/semantickernel-settings-loader</module> -->
<module>extensions/semantickernel-settings-loader</module>
<!-- <module>plugins/semantickernel-plugin-core</module> -->
<module>plugins/semantickernel-plugin-core</module>
<module>semantickernel-bom</module>
<module>semantickernel-api</module>
<!-- <module>semantickernel-core</module> -->
<module>semantickernel-core</module>
</modules>
<dependencyManagement>
@@ -717,13 +717,13 @@
</build>
</profile>
<profile>
<id>with-samples</id>
<modules>
<module>samples</module>
<module>api-test</module>
</modules>
</profile>
<!-- <profile>-->
<!-- <id>with-samples</id>-->
<!-- <modules>-->
<!-- <module>samples</module>-->
<!-- <module>api-test</module>-->
<!-- </modules>-->
<!-- </profile>-->
<profile>
<id>release</id>
<properties>
@@ -1,11 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.ai.embeddings.TextEmbeddingGeneration;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.BuildersSingleton;
@@ -17,9 +12,13 @@ import com.microsoft.semantickernel.orchestration.SKFunction;
import com.microsoft.semantickernel.plugin.Plugin;
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
import com.microsoft.semantickernel.services.AIService;
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import reactor.core.publisher.Mono;
/** Interface for the semantic kernel. */
@@ -53,7 +52,7 @@ public interface Kernel extends Buildable {
*
* @param pipeline List of functions
* @return Result of the function composition
* @apiNote Breaking change: s/SKFunction<?>/SKFunction/, s/Mono<SKContext>/Mono<KernelResult>/
* @apiNote Breaking change: s/SKFunction/SKFunction/, s/Mono<SKContext>/Mono<KernelResult>/
*/
@Deprecated
Mono<KernelResult> runAsync(SKFunction... pipeline);
@@ -64,7 +63,7 @@ public interface Kernel extends Buildable {
* @param input Input to process
* @param pipeline List of functions
* @return Result of the function composition
* @apiNote Breaking change: s/SKFunction<?>/SKFunction/, s/Mono<SKContext>/Mono<KernelResult>/
* @apiNote Breaking change: s/SKFunction/SKFunction/, s/Mono<SKContext>/Mono<KernelResult>/
*/
@Deprecated
Mono<KernelResult> runAsync(String input, SKFunction... pipeline);
@@ -75,19 +74,21 @@ public interface Kernel extends Buildable {
* @param variables variables to initialise the context with
* @param pipeline List of functions
* @return Result of the function composition
* @apiNote Breaking change: s/SKFunction<?>/SKFunction/, s/Mono<SKContext>/Mono<KernelResult>/
* @apiNote Breaking change: s/SKFunction/SKFunction/, s/Mono<SKContext>/Mono<KernelResult>/
*/
Mono<KernelResult> runAsync(ContextVariables variables, SKFunction... pipeline);
/**
* Run a pipeline composed of synchronous and asynchronous functions.
*
* @param streaming Whether to stream the results of the pipeline
* @param variables variables to initialise the context with
* @param pipeline List of functions
* @return Result of the function composition
* @since 1.0.0
*/
Mono<KernelResult> runAsync(boolean streaming, ContextVariables variables, SKFunction... pipeline);
Mono<KernelResult> runAsync(
boolean streaming, ContextVariables variables, SKFunction... pipeline);
/**
* Register a semantic function on this kernel
@@ -113,15 +114,20 @@ public interface Kernel extends Buildable {
<T extends AIService> T getService(@Nullable String name, Class<T> clazz)
throws KernelException;
/** Registers a semantic function on this kernel
* @apiNote Breaking change: s/<RequestConfiguration, FunctionType extends SKFunction<RequestConfiguration>>/<FunctionType extends SKFunction>/
*/
/**
* Registers a semantic function on this kernel
*
* @apiNote Breaking change: s/<RequestConfiguration, FunctionType extends
* SKFunction>/<FunctionType extends SKFunction>/
*/
@Deprecated
<FunctionType extends SKFunction>
FunctionType registerSemanticFunction(FunctionType semanticFunctionDefinition);
<FunctionType extends SKFunction> FunctionType registerSemanticFunction(
FunctionType semanticFunctionDefinition);
/** Obtains a semantic function with the given name
* @apiNote Breaking change: s/SKFunction<?>/SKFunction/
/**
* Obtains a semantic function with the given name
*
* @apiNote Breaking change: s/SKFunction/SKFunction/
*/
@Deprecated
SKFunction getFunction(String skill, String function);
@@ -130,6 +136,12 @@ public interface Kernel extends Buildable {
return BuildersSingleton.INST.getInstance(Kernel.Builder.class);
}
@Deprecated
ReadOnlySkillCollection getSkills();
@Deprecated
ReadOnlyFunctionCollection getSkill();
interface Builder extends SemanticKernelBuilder<Kernel> {
/**
* Set the kernel configuration
@@ -244,6 +256,7 @@ public interface Kernel extends Buildable {
/**
* Add plugins to the kernel to be built.
*
* @param plugins Plugins to add.
* @return Updated kernel builder including the plugins.
* @since 1.0.0
@@ -1,8 +1,8 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel;
import java.util.Collection;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import java.util.Collection;
/**
* @since 1.0.0
@@ -11,8 +11,8 @@ public interface KernelResult {
/**
* Get the results from all functions in pipeline.
*
* @return The results from all functions in pipeline.
*/
Collection<FunctionResult> functionResults();
}
@@ -1,8 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.chatcompletion;
import javax.annotation.Nullable;
import com.azure.ai.openai.OpenAIAsyncClient;
import com.azure.ai.openai.models.ChatCompletions;
import com.microsoft.semantickernel.builders.Buildable;
@@ -10,7 +8,7 @@ import com.microsoft.semantickernel.builders.BuildersSingleton;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.services.AIService;
import com.microsoft.semantickernel.textcompletion.TextCompletion;
import javax.annotation.Nullable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -36,7 +34,7 @@ public interface ChatCompletion<ChatHistoryType extends ChatHistory>
*/
ChatHistoryType createNewChat(String instructions);
/**
/**
* Create a new empty chat instance
*
* @return Chat object
@@ -44,7 +42,6 @@ public interface ChatCompletion<ChatHistoryType extends ChatHistory>
*/
ChatHistoryType createNewChat();
Flux<String> generateMessageStream(
ChatHistoryType chatHistory, @Nullable ChatRequestSettings requestSettings);
@@ -90,13 +90,12 @@ public class ChatHistory {
public void addMessage(AuthorRoles authorRole, String content) {
this.messages.add(new Message(authorRole, content));
}
/**
* Add a message to the chat history with the user as the author
*
* @param content Message content
* @since 1.0.0
* @
* @since 1.0.0 @
*/
public void addUserMessage(String content) {
this.messages.add(new Message(AuthorRoles.User, content));
@@ -111,5 +110,4 @@ public class ChatHistory {
public void addAssistantMessage(String content) {
this.messages.add(new Message(AuthorRoles.Assistant, content));
}
}
@@ -1,13 +1,12 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.nativefunction;
import java.util.Collection;
import com.microsoft.semantickernel.orchestration.SKFunction;
import java.util.Collection;
public class NativeFunction {
public static Collection<SKFunction> getFunctionsFromObject(Object object) {
return null;
}
}
@@ -105,12 +105,6 @@ public abstract class AbstractSKContext implements SKContext {
return getThis();
}
@Override
public SKContext appendToVariable(@Nonnull String key, @Nonnull String content) {
variables.appendToVariable(key, content);
return getThis();
}
@Override
public SKContext update(@Nonnull String content) {
variables.update(content);
@@ -1,14 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.orchestration;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.SKBuilders;
import com.microsoft.semantickernel.memory.NullMemory;
import com.microsoft.semantickernel.memory.SemanticTextMemory;
@@ -17,12 +9,16 @@ import com.microsoft.semantickernel.skilldefinition.KernelSkillsSupplier;
import com.microsoft.semantickernel.skilldefinition.ParameterView;
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
import com.microsoft.semantickernel.skilldefinition.annotations.SKFunctionParameters;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import reactor.core.publisher.Mono;
/** Abstract implementation of the SKFunction interface. */
public abstract class AbstractSkFunction
implements SKFunction, RegistrableSkFunction {
public abstract class AbstractSKFunction implements SKFunction, RegistrableSkFunction {
private final List<ParameterView> parameters;
private final String skillName;
@@ -41,7 +37,7 @@ public abstract class AbstractSkFunction
* @param description The description of the function.
* @param skillsSupplier The skill supplier.
*/
public AbstractSkFunction(
public AbstractSKFunction(
List<ParameterView> parameters,
String skillName,
String functionName,
@@ -87,12 +83,12 @@ public abstract class AbstractSkFunction
return skillsSupplier;
}
/** @apiNote Breaking change: s/RequestConfiguration settings/Object settings/ */
/**
* @apiNote Breaking change: s/RequestConfiguration settings/Object settings/
*/
@Override
public Mono<SKContext> invokeAsync(
@Nullable String input,
@Nullable SKContext context,
@Nullable Object settings) {
@Nullable String input, @Nullable SKContext context, @Nullable Object settings) {
if (context == null) {
assertSkillSupplierRegistered();
@@ -117,10 +113,11 @@ public abstract class AbstractSkFunction
return invokeAsync(input, null, null);
}
/** @apiNote Breaking change: s/RequestConfiguration settings/Object settings/ */
/**
* @apiNote Breaking change: s/RequestConfiguration settings/Object settings/
*/
@Override
public Mono<SKContext> invokeAsync(
@Nullable SKContext context, @Nullable Object settings) {
public Mono<SKContext> invokeAsync(@Nullable SKContext context, @Nullable Object settings) {
if (context == null) {
context =
SKBuilders.context()
@@ -3,13 +3,11 @@ package com.microsoft.semantickernel.orchestration;
// Copyright (c) Microsoft. All rights reserved.
import java.util.Map;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.BuildersSingleton;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import java.util.Map;
import javax.annotation.Nullable;
/**
* Context Variables is a data structure that holds temporary data while a task is being performed.
@@ -41,7 +39,7 @@ public interface ContextVariables extends Buildable {
* @return input
*/
@Nullable
String getInput();
Object getInput();
/**
* Create formatted string of the variables
@@ -1,55 +1,56 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.orchestration;
import java.util.Map;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* @since 1.0.0
*/
public interface FunctionResult {
/**
* Get the name of executed function.
*
* @return The name of executed function.
*/
String functionName();
/**
* Get the name of the plugin containing the function.
*
* @return The name of the plugin containing the function.
*/
String pluginName();
/**
* Get the metadata for storing additional information about function execution result.
*
* @return The metadata for storing additional information about function execution result.
*/
Map<String, Object> metadata();
/**
* Get the function result.
*
* @return The function result.
* @param <T> The type of the function result.
*/
<T> Mono<T> getValueAsync();
Mono<String> getValueAsync();
/**
* Get the function result.
*
* @return The function result.
* @param <T> The type of the function result.
*/
<T> Flux<T> getStreamingValueAsync();
Flux<String> getStreamingValueAsync();
/**
* Get the function result.
*
* @return The function result.
* @param <T> The type of the function result.
*/
<T> T getValue();
String getValue();
/**
* Get typed data from metadata.
@@ -1,15 +1,13 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.orchestration;
import javax.annotation.CheckReturnValue;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.BuildersSingleton;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.memory.SemanticTextMemory;
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
import javax.annotation.CheckReturnValue;
import reactor.util.annotation.Nullable;
/** Semantic Kernel context. */
@@ -20,8 +18,6 @@ public interface SKContext extends Buildable {
@Nullable SemanticTextMemory memory,
@Nullable ReadOnlySkillCollection skills);
/**
* Obtain the result of the execution that produced this context. This will be the "input" entry
* in the variables.
@@ -1,21 +1,19 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.orchestration;
import java.util.Map;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.KernelResult;
import com.microsoft.semantickernel.memory.SemanticTextMemory;
import com.microsoft.semantickernel.skilldefinition.FunctionView;
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;
import reactor.core.publisher.Mono;
/**
* Semantic Kernel callable function interface
* @apiNote Breaking change: s/SKFunction<RequestConfiguration>/SKFunction/
*
* @apiNote Breaking change: s/SKFunction/SKFunction/
*/
public interface SKFunction {
/**
@@ -58,9 +56,7 @@ public interface SKFunction {
/**
* The type of the configuration argument that will be provided when the function is invoked
*
* @return The type
@Nullable
Class<RequestConfiguration> getType();
* @return The type @Nullable Class<RequestConfiguration> getType();
*/
/**
@@ -70,8 +66,26 @@ public interface SKFunction {
* @return an updated context with the result of the request
*/
@CheckReturnValue
@Deprecated
Mono<SKContext> invokeAsync(SKContext context);
/**
* The type of the configuration argument that will be provided when the function is invoked
*
* @return The type @Nullable Class<RequestConfiguration> getType();
*/
/**
* Invokes the function with the given context and settings
*
* @param kernel Associated Kernel
* @param variables Request variables
* @param streaming Whether streaming is on or not
* @return an updated context with the result of the request
*/
@CheckReturnValue
Mono<FunctionResult> invokeAsync(Kernel kernel, ContextVariables variables, boolean streaming);
/**
* Invokes the function with the given context and settings
*
@@ -82,16 +96,8 @@ public interface SKFunction {
*/
@CheckReturnValue
@Deprecated
Mono<SKContext> invokeAsync(SKContext context, @Nullable Object settings);
Mono<SKContext> invokeAsync(SKContext context, @Nullable Object settings);
/**
* @return The result of invoking the function.
* @param kernel The kernel to invoke the function on
* @param variables The variables to invoke the function with
* @since 1.0.0
*/
Mono<FunctionResult> invokeAsync(Kernel kernel, Map<String,Object> variables);
/**
* @return The name of the skill that this function is within
*/
@@ -19,16 +19,6 @@ public interface WritableContextVariables extends ContextVariables {
*/
ContextVariables setVariable(String key, Object content);
/**
* Append to the variable's value
*
* @param key variable name
* @param content value to append
* @return Context for fluent calls
* @apiNote Breaking change: s/String content/Object content/
*/
ContextVariables appendToVariable(String key, Object content);
/**
* Updates the main input text with the new value after a function is complete.
*
@@ -1,8 +1,8 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.plugin;
import java.util.Collection;
import com.microsoft.semantickernel.orchestration.SKFunction;
import java.util.Collection;
public interface Plugin {
String name();
@@ -4,6 +4,7 @@ package com.microsoft.semantickernel.semanticfunctions;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.BuildersSingleton;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.orchestration.ContextVariables;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.skilldefinition.ParameterView;
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
@@ -25,8 +26,11 @@ public interface PromptTemplate extends Buildable {
* @param executionContext Kernel execution context helpers
* @return Prompt rendered to string
*/
@Deprecated
Mono<String> renderAsync(SKContext executionContext);
Mono<String> renderAsync(ContextVariables variables);
static Builder builder() {
return BuildersSingleton.INST.getInstance(Builder.class);
}
@@ -1,14 +1,13 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.skilldefinition;
import java.util.function.Supplier;
import com.microsoft.semantickernel.Kernel;
import java.util.function.Supplier;
public interface KernelSkillsSupplier extends Supplier<ReadOnlySkillCollection> {
@Deprecated
static KernelSkillsSupplier getInstance(Kernel kernel) {
return null; //kernel::getSkills;
return null; // kernel::getSkills;
}
}
@@ -1,13 +1,11 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.skilldefinition;
import com.microsoft.semantickernel.orchestration.SKFunction;
import java.util.List;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.orchestration.SKFunction;
public interface ReadOnlyFunctionCollection {
String getSkillName();
@@ -1,15 +1,13 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.skilldefinition;
import java.util.Map;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.BuildersSingleton;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.orchestration.SKFunction;
import java.util.Map;
import javax.annotation.CheckReturnValue;
import javax.annotation.Nullable;
/**
* Skill collection interface.
@@ -36,7 +34,9 @@ public interface ReadOnlySkillCollection extends Buildable {
ReadOnlyFunctionCollection getAllFunctions();
/** Get function with name from the global scope
/**
* Get function with name from the global scope
*
* @apiNote Breaking change: s/SKFunciton<?>/SKFunction/
*/
@Nullable
@@ -4,6 +4,7 @@ package com.microsoft.semantickernel.templateengine;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.BuildersSingleton;
import com.microsoft.semantickernel.builders.SemanticKernelBuilder;
import com.microsoft.semantickernel.orchestration.ContextVariables;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.templateengine.blocks.Block;
import java.util.List;
@@ -34,6 +35,16 @@ public interface PromptTemplateEngine extends Buildable {
*/
Mono<String> renderAsync(String templateText, SKContext context);
/**
* Given a prompt template, replace the variables with their values and execute the functions
* replacing their reference with the function result
*
* @param templateText Prompt template (see skprompt.txt files)
* @param variables ContextVariables with the associated values
* @return The prompt template ready to be used for an AI request
*/
Mono<String> renderAsync(String templateText, ContextVariables variables);
/**
* Given a prompt template string, extract all the blocks (text, variables, function calls)
*
@@ -1,10 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.textcompletion;
import java.util.List;
import javax.annotation.Nullable;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.builders.BuildersSingleton;
@@ -13,7 +9,8 @@ import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.orchestration.SKFunction;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig;
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
import java.util.List;
import javax.annotation.Nullable;
import reactor.core.publisher.Mono;
/** Semantic function for text completion */
+31 -5
View File
@@ -81,15 +81,41 @@
<artifactId>semantickernel-plugin-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.microsoft.semantic-kernel</groupId>
<artifactId>semantickernel-planners</artifactId>
<scope>test</scope>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.microsoft.semantic-kernel</groupId>-->
<!-- <artifactId>semantickernel-planners</artifactId>-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
</dependency>
<dependency>
<groupId>com.github.jknack</groupId>
<artifactId>handlebars</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.15.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.15.2</version>
</dependency>
</dependencies>
</project>
@@ -3,36 +3,33 @@ package com.microsoft.semantickernel;
import com.microsoft.semantickernel.ai.AIException;
import com.microsoft.semantickernel.ai.embeddings.TextEmbeddingGeneration;
import com.microsoft.semantickernel.coreskills.SkillImporter;
import com.microsoft.semantickernel.exceptions.SkillsNotFoundException;
import com.microsoft.semantickernel.exceptions.SkillsNotFoundException.ErrorCodes;
import com.microsoft.semantickernel.extensions.KernelExtensions;
import com.microsoft.semantickernel.memory.MemoryConfiguration;
import com.microsoft.semantickernel.memory.MemoryStore;
import com.microsoft.semantickernel.memory.NullMemory;
import com.microsoft.semantickernel.memory.SemanticTextMemory;
import com.microsoft.semantickernel.orchestration.ContextVariables;
import com.microsoft.semantickernel.orchestration.RegistrableSkFunction;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.orchestration.SKFunction;
import com.microsoft.semantickernel.orchestration.*;
import com.microsoft.semantickernel.plugin.Plugin;
import com.microsoft.semantickernel.semanticfunctions.SemanticFunctionConfig;
import com.microsoft.semantickernel.services.AIService;
import com.microsoft.semantickernel.services.AIServiceCollection;
import com.microsoft.semantickernel.services.AIServiceProvider;
import com.microsoft.semantickernel.skilldefinition.DefaultSkillCollection;
import com.microsoft.semantickernel.skilldefinition.FunctionNotFound;
import com.microsoft.semantickernel.skilldefinition.ReadOnlyFunctionCollection;
import com.microsoft.semantickernel.skilldefinition.ReadOnlySkillCollection;
import com.microsoft.semantickernel.templateengine.DefaultPromptTemplateEngine;
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
import com.microsoft.semantickernel.textcompletion.CompletionSKFunction;
import jakarta.inject.Inject;
import java.util.List;
import java.util.Arrays;
import java.util.Map;
import java.util.ArrayList;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public class DefaultKernel implements Kernel {
@@ -83,24 +80,31 @@ public class DefaultKernel implements Kernel {
}
}
@Override
public <FunctionType extends SKFunction> FunctionType registerSemanticFunction(
FunctionType semanticFunctionDefinition) {
return null;
}
@Override
public KernelConfig getConfig() {
return kernelConfig;
}
@Override
public <RequestConfiguration, FunctionType extends SKFunction<RequestConfiguration>>
FunctionType registerSemanticFunction(FunctionType func) {
if (!(func instanceof RegistrableSkFunction)) {
throw new RuntimeException("This function does not implement RegistrableSkFunction");
}
((RegistrableSkFunction) func).registerOnKernel(this);
defaultSkillCollection.addSemanticFunction(func);
return func;
}
// @Override
// public <RequestConfiguration, FunctionType extends SKFunction>
// FunctionType registerSemanticFunction(FunctionType func) {
// if (!(func instanceof RegistrableSkFunction)) {
// throw new RuntimeException("This function does not implement
// RegistrableSkFunction");
// }
// ((RegistrableSkFunction) func).registerOnKernel(this);
// defaultSkillCollection.addSemanticFunction(func);
// return func;
// }
@Override
public SKFunction<?> getFunction(String skill, String function) {
public SKFunction getFunction(String skill, String function) {
return defaultSkillCollection.getFunction(skill, function, null);
}
@@ -130,118 +134,129 @@ public class DefaultKernel implements Kernel {
// value is empty functions are registered in the global namespace.</param>
/// <returns>A list of all the semantic functions found in the directory, indexed by function
// name.</returns>
@Override
public ReadOnlyFunctionCollection importSkill(
String skillName, Map<String, SemanticFunctionConfig> skills)
throws SkillsNotFoundException {
skills.entrySet().stream()
.map(
(entry) -> {
return SKBuilders.completionFunctions()
.withKernel(this)
.withSkillName(skillName)
.withFunctionName(entry.getKey())
.withSemanticFunctionConfig(entry.getValue())
.build();
})
.forEach(this::registerSemanticFunction);
ReadOnlyFunctionCollection collection = getSkill(skillName);
if (collection == null) {
throw new SkillsNotFoundException(ErrorCodes.SKILLS_NOT_FOUND);
}
return collection;
}
@Override
public ReadOnlyFunctionCollection importSkill(
Object skillInstance, @Nullable String skillName) {
if (skillInstance instanceof String) {
throw new KernelException(
KernelException.ErrorCodes.FUNCTION_NOT_AVAILABLE,
"Called importSkill with a string argument, it is likely the intention was to"
+ " call importSkillFromDirectory");
}
if (skillName == null || skillName.isEmpty()) {
skillName = ReadOnlySkillCollection.GlobalSkill;
}
// skill = new Dictionary<string, ISKFunction>(StringComparer.OrdinalIgnoreCase);
ReadOnlyFunctionCollection functions =
SkillImporter.importSkill(skillInstance, skillName, () -> defaultSkillCollection);
DefaultSkillCollection newSkills =
functions.getAll().stream()
.reduce(
new DefaultSkillCollection(),
DefaultSkillCollection::addNativeFunction,
DefaultSkillCollection::merge);
this.defaultSkillCollection.merge(newSkills);
return functions;
}
// @Override
// public ReadOnlyFunctionCollection importSkill(
// String skillName, Map<String, SemanticFunctionConfig> skills)
// throws SkillsNotFoundException {
// skills.entrySet().stream()
// .map(
// (entry) -> {
// return SKBuilders.completionFunctions()
// .withKernel(this)
// .withSkillName(skillName)
// .withFunctionName(entry.getKey())
// .withSemanticFunctionConfig(entry.getValue())
// .build();
// })
// .forEach(this::registerSemanticFunction);
//
// ReadOnlyFunctionCollection collection = getSkill(skillName);
// if (collection == null) {
// throw new SkillsNotFoundException(ErrorCodes.SKILLS_NOT_FOUND);
// }
// return collection;
// }
//
// @Override
// public ReadOnlyFunctionCollection importSkill(
// Object skillInstance, @Nullable String skillName) {
// if (skillInstance instanceof String) {
// throw new KernelException(
// KernelException.ErrorCodes.FUNCTION_NOT_AVAILABLE,
// "Called importSkill with a string argument, it is likely the intention was
// to"
// + " call importSkillFromDirectory");
// }
//
// if (skillName == null || skillName.isEmpty()) {
// skillName = ReadOnlySkillCollection.GlobalSkill;
// }
//
// // skill = new Dictionary<string, ISKFunction>(StringComparer.OrdinalIgnoreCase);
// ReadOnlyFunctionCollection functions =
// SkillImporter.importSkill(skillInstance, skillName, () ->
// defaultSkillCollection);
//
// DefaultSkillCollection newSkills =
// functions.getAll().stream()
// .reduce(
// new DefaultSkillCollection(),
// DefaultSkillCollection::addNativeFunction,
// DefaultSkillCollection::merge);
//
// this.defaultSkillCollection.merge(newSkills);
//
// return functions;
// }
@Override
public ReadOnlySkillCollection getSkills() {
return defaultSkillCollection;
}
@Override
public ReadOnlyFunctionCollection getSkill() {
return null;
}
@Override
public CompletionSKFunction.Builder getSemanticFunctionBuilder() {
return SKBuilders.completionFunctions().withKernel(this);
}
@Override
public ReadOnlyFunctionCollection getSkill(String skillName) throws FunctionNotFound {
ReadOnlyFunctionCollection functions = this.defaultSkillCollection.getFunctions(skillName);
if (functions == null) {
throw new FunctionNotFound(FunctionNotFound.ErrorCodes.FUNCTION_NOT_FOUND, skillName);
}
return functions;
}
@Override
public ReadOnlyFunctionCollection importSkillFromDirectory(
String skillName, String parentDirectory, String skillDirectoryName) {
Map<String, SemanticFunctionConfig> skills =
KernelExtensions.importSemanticSkillFromDirectory(
parentDirectory, skillDirectoryName, promptTemplateEngine);
return importSkill(skillName, skills);
}
@Override
public void importSkillsFromDirectory(String parentDirectory, String... skillNames) {
Arrays.stream(skillNames)
.forEach(
skill -> {
importSkillFromDirectory(skill, parentDirectory, skill);
});
}
@Override
public ReadOnlyFunctionCollection importSkillFromDirectory(
String skillName, String parentDirectory) {
return importSkillFromDirectory(skillName, parentDirectory, skillName);
}
@Override
public ReadOnlyFunctionCollection importSkillFromResources(
String pluginDirectory, String skillName, String functionName) {
return importSkillFromResources(pluginDirectory, skillName, functionName, null);
}
@Override
public ReadOnlyFunctionCollection importSkillFromResources(
String pluginDirectory, String skillName, String functionName, @Nullable Class clazz)
throws KernelException {
Map<String, SemanticFunctionConfig> skills =
KernelExtensions.importSemanticSkillFromResourcesDirectory(
pluginDirectory, skillName, functionName, clazz, promptTemplateEngine);
return importSkill(skillName, skills);
}
// @Override
// public ReadOnlyFunctionCollection getSkill(String skillName) throws FunctionNotFound {
// ReadOnlyFunctionCollection functions =
// this.defaultSkillCollection.getFunctions(skillName);
// if (functions == null) {
// throw new FunctionNotFound(FunctionNotFound.ErrorCodes.FUNCTION_NOT_FOUND,
// skillName);
// }
//
// return functions;
// }
//
// @Override
// public ReadOnlyFunctionCollection importSkillFromDirectory(
// String skillName, String parentDirectory, String skillDirectoryName) {
// Map<String, SemanticFunctionConfig> skills =
// KernelExtensions.importSemanticSkillFromDirectory(
// parentDirectory, skillDirectoryName, promptTemplateEngine);
// return importSkill(skillName, skills);
// }
//
// @Override
// public void importSkillsFromDirectory(String parentDirectory, String... skillNames) {
// Arrays.stream(skillNames)
// .forEach(
// skill -> {
// importSkillFromDirectory(skill, parentDirectory, skill);
// });
// }
//
// @Override
// public ReadOnlyFunctionCollection importSkillFromDirectory(
// String skillName, String parentDirectory) {
// return importSkillFromDirectory(skillName, parentDirectory, skillName);
// }
//
// @Override
// public ReadOnlyFunctionCollection importSkillFromResources(
// String pluginDirectory, String skillName, String functionName) {
// return importSkillFromResources(pluginDirectory, skillName, functionName, null);
// }
//
// @Override
// public ReadOnlyFunctionCollection importSkillFromResources(
// String pluginDirectory, String skillName, String functionName, @Nullable Class
// clazz)
// throws KernelException {
// Map<String, SemanticFunctionConfig> skills =
// KernelExtensions.importSemanticSkillFromResourcesDirectory(
// pluginDirectory, skillName, functionName, clazz,
// promptTemplateEngine);
// return importSkill(skillName, skills);
// }
@Override
public PromptTemplateEngine getPromptTemplateEngine() {
@@ -258,54 +273,37 @@ public class DefaultKernel implements Kernel {
}
@Override
public Mono<SKContext> runAsync(SKFunction<?>... pipeline) {
public Mono<KernelResult> runAsync(SKFunction... pipeline) {
return runAsync(SKBuilders.variables().build(), pipeline);
}
@Override
public Mono<SKContext> runAsync(String input, SKFunction<?>... pipeline) {
public Mono<KernelResult> runAsync(String input, SKFunction... pipeline) {
return runAsync(SKBuilders.variables().withInput(input).build(), pipeline);
}
@Override
public Mono<SKContext> runAsync(ContextVariables variables, SKFunction<?>... pipeline) {
public Mono<KernelResult> runAsync(ContextVariables variables, SKFunction... pipeline) {
return null;
}
@Override
public Mono<KernelResult> runAsync(
boolean streaming, ContextVariables variables, SKFunction... pipeline) {
// TODO: 1.0 support pipeline
if (pipeline == null || pipeline.length == 0) {
throw new SKException("No parameters provided to pipeline");
}
// TODO: The SemanticTextMemory can be null, but there should be a way to provide it.
// Not sure registerMemory is the right way.
Mono<SKContext> pipelineBuilder =
Mono.just(
SKBuilders.context()
.withVariables(variables)
.withSkills(getSkills())
.build());
List<Mono<FunctionResult>> results = new ArrayList<>();
for (SKFunction f : Arrays.asList(pipeline)) {
pipelineBuilder =
pipelineBuilder
.switchIfEmpty(
Mono.fromCallable(
() -> {
// Previous pipeline did not produce a result
return SKBuilders.context()
.withVariables(variables)
.withSkills(getSkills())
.build();
}))
.flatMap(
newContext -> {
SKContext context =
SKBuilders.context()
.withVariables(newContext.getVariables())
.withMemory(newContext.getSemanticMemory())
.withSkills(newContext.getSkills())
.build();
return f.invokeAsync(context, null);
});
results.add(f.invokeAsync(this, variables, streaming));
}
return pipelineBuilder;
return Flux.merge(results)
.collectList()
.map(DefaultKernelResult::new);
}
public static class Builder implements Kernel.Builder {
@@ -464,6 +462,11 @@ public class DefaultKernel implements Kernel {
return this;
}
@Override
public Kernel.Builder withPlugins(Plugin... plugins) {
return null;
}
/**
* Build the kernel
*
@@ -0,0 +1,19 @@
package com.microsoft.semantickernel;
import com.microsoft.semantickernel.KernelResult;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import java.util.Collection;
public class DefaultKernelResult implements KernelResult {
private Collection<FunctionResult> results;
public DefaultKernelResult(Collection<FunctionResult> results) {
this.results = results;
}
@Override
public Collection<FunctionResult> functionResults() {
return this.results;
}
}
@@ -0,0 +1,66 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.functions;
import com.microsoft.semantickernel.orchestration.FunctionResult;
import com.microsoft.semantickernel.semanticfunctions.SemanticFunction;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Map;
public class SemanticFunctionResult implements FunctionResult {
private Mono<String> valueAsync;
private Flux<String> streamingValueAsync;
private boolean isStreaming;
private String functionName;
private String pluginName;
private Map<String, Object> metadata;
public SemanticFunctionResult() {}
public SemanticFunctionResult(String pluginName, String functionName, Mono<String> valueAsync) {
this.valueAsync = valueAsync;
this.pluginName = pluginName;
this.functionName = functionName;
this.isStreaming = false;
}
public SemanticFunctionResult(String pluginName, String functionName, Mono<String> valueAsync, Flux<String> streamingValueAsync) {
this.pluginName = pluginName;
this.functionName = functionName;
this.valueAsync = valueAsync;
this.isStreaming = true;
this.streamingValueAsync = streamingValueAsync;
}
@Override
public String functionName() {
return null;
}
@Override
public String pluginName() {
return null;
}
@Override
public Map<String, Object> metadata() {
return null;
}
@Override
public Flux<String> getStreamingValueAsync() {
return streamingValueAsync;
}
@Override
public Mono<String> getValueAsync() {
return valueAsync;
}
@Override
public String getValue() {
return valueAsync.block();
}
}
@@ -32,8 +32,7 @@ import reactor.core.publisher.Mono;
// cref="Action"/>,
/// with additional methods required by the kernel.
/// </summary>
public class DefaultCompletionSKFunction
extends DefaultSemanticSKFunction<CompletionRequestSettings>
public class DefaultCompletionSKFunction extends DefaultSemanticSKFunction
implements CompletionSKFunction {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCompletionSKFunction.class);
@@ -138,9 +137,10 @@ public class DefaultCompletionSKFunction
.skip(1) // Skip the first element, which is the initial context
.concatMap(it -> it);
// TODO: fix
return results.map(
result -> {
return result.getResult();
return (String) result.getResult();
})
.collect(Collectors.joining("\n"))
.map(context::update);
@@ -148,8 +148,7 @@ public class DefaultCompletionSKFunction
// Run the semantic function
@Override
protected Mono<SKContext> invokeAsyncInternal(
SKContext context, @Nullable CompletionRequestSettings settings) {
protected Mono<SKContext> invokeAsyncInternal(SKContext context, @Nullable Object settings) {
// TODO
// this.VerifyIsSemantic();
// this.ensureContextHasSkills(context);
@@ -167,7 +166,8 @@ public class DefaultCompletionSKFunction
throw new IllegalStateException("Failed to initialise aiService");
}
CompletionRequestSettings finalSettings = settings;
// TODO: 1.0 fix properly using settings object
CompletionRequestSettings finalSettings = new CompletionRequestSettings(0.9, 0, 0, 0, 1000);
return function.run(this.aiService.get(), finalSettings, context)
.map(
@@ -257,11 +257,6 @@ public class DefaultCompletionSKFunction
}
}
@Override
public Class<CompletionRequestSettings> getType() {
return CompletionRequestSettings.class;
}
private static String randomFunctionName() {
return "func" + UUID.randomUUID();
}
@@ -277,6 +272,11 @@ public class DefaultCompletionSKFunction
false);
}
@Override
public Mono<FunctionResult> invokeAsync(Kernel kernel, ContextVariables variables, boolean streaming) {
return null;
}
public static class Builder implements CompletionSKFunction.Builder {
private Kernel kernel;
@@ -13,7 +13,7 @@ import reactor.util.annotation.NonNull;
/// </summary>
class DefaultContextVariables implements ContextVariables, WritableContextVariables {
private final CaseInsensitiveMap<String> variables;
private final CaseInsensitiveMap<Object> variables;
/// <summary>
/// In the simplest scenario, the data is an input string, stored here.
@@ -24,37 +24,23 @@ class DefaultContextVariables implements ContextVariables, WritableContextVariab
/// Constructor for context variables.
/// </summary>
/// <param name="content">Optional value for the main variable of the context.</param>
DefaultContextVariables(@NonNull String content) {
DefaultContextVariables(@NonNull Object content) {
this.variables = new CaseInsensitiveMap<>();
this.variables.put(MAIN_KEY, content);
}
DefaultContextVariables(Map<String, String> variables) {
DefaultContextVariables(Map<String, Object> variables) {
this.variables = new CaseInsensitiveMap<>(variables);
}
@Override
public ContextVariables setVariable(@NonNull String key, @NonNull String content) {
public ContextVariables setVariable(@NonNull String key, @NonNull Object content) {
this.variables.put(key, content);
return this;
}
@Override
public ContextVariables appendToVariable(@NonNull String key, @NonNull String content) {
String existing = this.variables.get(key);
String newVal;
if (existing == null) {
newVal = content;
} else {
newVal = existing + content;
}
return setVariable(key, newVal);
}
@Override
public Map<String, String> asMap() {
public Map<String, Object> asMap() {
return Collections.unmodifiableMap(variables);
}
@@ -66,7 +52,7 @@ class DefaultContextVariables implements ContextVariables, WritableContextVariab
/// if the pipeline reached the end.</param>
/// <returns>The current instance</returns>
@Override
public ContextVariables update(@NonNull String content) {
public ContextVariables update(@NonNull Object content) {
return setVariable(MAIN_KEY, content);
}
@@ -82,7 +68,6 @@ class DefaultContextVariables implements ContextVariables, WritableContextVariab
/// <param name="merge">Whether to merge and keep old data, or replace. False == discard old
// data.</param>
/// <returns>The current instance</returns>
@Override
public DefaultContextVariables update(@NonNull ContextVariables newData, boolean merge) {
/*
@@ -112,7 +97,7 @@ class DefaultContextVariables implements ContextVariables, WritableContextVariab
@Override
@Nullable
public String getInput() {
public Object getInput() {
return get(MAIN_KEY);
}
@@ -132,28 +117,28 @@ class DefaultContextVariables implements ContextVariables, WritableContextVariab
@Override
@Nullable
public String get(String key) {
public Object get(String key) {
return variables.get(key);
}
public static class WritableBuilder implements WritableContextVariables.Builder {
@Override
public WritableContextVariables build(Map<String, String> map) {
public WritableContextVariables build(Map<String, Object> map) {
return new DefaultContextVariables(map);
}
}
public static class Builder implements ContextVariables.Builder {
private final Map<String, String> variables;
private final Map<String, Object> variables;
public Builder() {
variables = new CaseInsensitiveMap<>();
this.variables.put(MAIN_KEY, "");
// this.variables.put(MAIN_KEY, "");
}
@Override
public ContextVariables.Builder withVariable(String key, String value) {
public ContextVariables.Builder withVariable(String key, Object value) {
variables.put(key, value);
return this;
}
@@ -165,7 +150,7 @@ class DefaultContextVariables implements ContextVariables, WritableContextVariab
}
@Override
public Builder withVariables(Map<String, String> map) {
public Builder withVariables(Map<String, Object> map) {
variables.putAll(map);
return this;
}
@@ -37,6 +37,11 @@ public class DefaultSKContext extends AbstractSKContext {
return new DefaultSKContext(variables, memory, skillCollection);
}
@Override
public SKContext appendToVariable(String key, String content) {
throw new RuntimeException("Append no longer supported in objects");
}
public static class Builder implements SKContext.Builder {
private ContextVariables variables;
@@ -16,9 +16,7 @@ import reactor.core.publisher.Mono;
// cref="Action"/>,
/// with additional methods required by the kernel.
/// </summary>
public abstract class DefaultSemanticSKFunction<RequestConfiguration>
extends AbstractSkFunction<RequestConfiguration>
implements SKFunction<RequestConfiguration> {
public abstract class DefaultSemanticSKFunction extends AbstractSKFunction implements SKFunction {
public DefaultSemanticSKFunction(
List<ParameterView> parameters,
@@ -37,9 +35,7 @@ public abstract class DefaultSemanticSKFunction<RequestConfiguration>
@Override
public Mono<SKContext> invokeAsync(
@Nullable String input,
@Nullable SKContext context,
@Nullable RequestConfiguration settings) {
@Nullable String input, @Nullable SKContext context, @Nullable Object settings) {
if (context == null) {
assertSkillSupplierRegistered();
context =
@@ -40,7 +40,7 @@ import reactor.core.scheduler.Schedulers;
// cref="Action"/>,
/// with additional methods required by the kernel.
/// </summary>
public class NativeSKFunction extends AbstractSkFunction<Void> {
public class NativeSKFunction extends AbstractSKFunction {
private static final Logger LOGGER = LoggerFactory.getLogger(NativeSKFunction.class);
@@ -76,8 +76,8 @@ public class NativeSKFunction extends AbstractSkFunction<Void> {
}
@Override
public Class<Void> getType() {
return Void.class;
public Mono<FunctionResult> invokeAsync(Kernel kernel, ContextVariables variables, boolean streaming) {
return null;
}
@Override
@@ -152,7 +152,7 @@ public class NativeSKFunction extends AbstractSkFunction<Void> {
// Run the native function
@Override
protected Mono<SKContext> invokeAsyncInternal(SKContext context, @Nullable Void settings) {
protected Mono<SKContext> invokeAsyncInternal(SKContext context, @Nullable Object settings) {
return this.function.run(context);
}
@@ -352,11 +352,12 @@ public class NativeSKFunction extends AbstractSkFunction<Void> {
Method method, SKContext context, Parameter parameter, Set<Parameter> inputArgs) {
String variableName = getGetVariableName(parameter);
String arg = context.getVariables().get(variableName);
// TODO: 1.0 fix cast
String arg = (String) context.getVariables().get(variableName);
if (arg == null) {
// If this is bound to input get the input value
if (inputArgs.contains(parameter)) {
String input = context.getVariables().get(ContextVariables.MAIN_KEY);
String input = (String) context.getVariables().get(ContextVariables.MAIN_KEY);
if (input != null) {
arg = input;
}
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.semanticfunctions;
import com.microsoft.semantickernel.orchestration.ContextVariables;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.skilldefinition.ParameterView;
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
@@ -68,6 +69,11 @@ public class DefaultPromptTemplate implements PromptTemplate {
return templateEngine.renderAsync(this.promptTemplate, executionContext);
}
@Override
public Mono<String> renderAsync(ContextVariables variables) {
return null;
}
public static final class Builder implements PromptTemplate.Builder {
@Nullable private String promptTemplate = null;
@Nullable private PromptTemplateConfig config = null;
@@ -0,0 +1,211 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.semanticfunctions;
import com.azure.core.exception.HttpResponseException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.microsoft.semantickernel.Kernel;
import com.microsoft.semantickernel.builders.Buildable;
import com.microsoft.semantickernel.functions.SemanticFunctionResult;
import com.microsoft.semantickernel.orchestration.*;
import com.microsoft.semantickernel.skilldefinition.FunctionView;
import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplate;
import com.microsoft.semantickernel.templateengine.handlebars.HandlebarsPromptTemplateEngine;
import com.microsoft.semantickernel.textcompletion.CompletionRequestSettings;
import com.microsoft.semantickernel.textcompletion.TextCompletion;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public class SemanticFunction extends DefaultSemanticSKFunction {
private static final Logger LOGGER = LoggerFactory.getLogger(DefaultCompletionSKFunction.class);
private String name;
private String pluginName;
private String description;
private List<SemanticFunctionModel.ExecutionSettingsModel> executionSettings;
private List<SemanticFunctionModel.VariableViewModel> inputParameters;
private PromptTemplate promptTemplate;
public SemanticFunction(
String name,
String pluginName,
String description,
List<SemanticFunctionModel.ExecutionSettingsModel> executionSettings,
PromptTemplate promptTemplate,
List<SemanticFunctionModel.VariableViewModel> inputParameters) {
super(Collections.emptyList(), name, name, description, null);
this.name = name;
this.pluginName = pluginName;
this.description = description;
this.executionSettings = executionSettings;
this.promptTemplate = promptTemplate;
this.inputParameters = inputParameters;
}
public static SemanticFunction fromYaml(String filePath) throws IOException {
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
InputStream inputStream =
SemanticFunction.class.getClassLoader().getResourceAsStream(filePath);
SemanticFunctionModel functionModel =
mapper.readValue(inputStream, SemanticFunctionModel.class);
return new Builder()
.withName(functionModel.getName())
.withInputParameters(functionModel.getInputVariables())
.withPromptTemplate(
new HandlebarsPromptTemplate(
functionModel.getTemplate(), new HandlebarsPromptTemplateEngine()))
.withPluginName(functionModel.getName()) // TODO: 1.0 add plugin name
.withExecutionSettings(functionModel.getExecutionSettings())
.withDescription(functionModel.getDescription())
.build();
}
@Override
public Mono<FunctionResult> invokeAsync(Kernel kernel, ContextVariables input, boolean streaming) {
TextCompletion client = kernel.getService(null, TextCompletion.class);
if (client == null) {
throw new IllegalStateException("Failed to initialise aiService");
}
// TODO: 1.0 check model pattern Id to select execution settings
SemanticFunctionModel.ExecutionSettingsModel executionSettingsModel =
this.executionSettings.get(0);
// TODO: 1.0 fix settings
CompletionRequestSettings requestSettings = new CompletionRequestSettings(
Double.valueOf(executionSettingsModel.getTemperature()), 0, 0, 0, 1000);
return this.promptTemplate
.renderAsync(input)
.flatMap(
prompt ->
performCompletionRequest(
client, requestSettings, prompt ,streaming))
.doOnError(
ex -> {
LOGGER.warn(
"Something went wrong while rendering the semantic"
+ " function or while executing the text"
+ " completion. Function: {}.{}. Error: {}",
getSkillName(),
getName(),
ex.getMessage());
// Common message when you attempt to send text completion
// requests to a chat completion model:
// "logprobs, best_of and echo parameters are not
// available on gpt-35-turbo model"
if (ex instanceof HttpResponseException
&& ((HttpResponseException) ex)
.getResponse()
.getStatusCode()
== 400
&& ex.getMessage()
.contains(
"parameters are not available"
+ " on")) {
LOGGER.warn(
"This error indicates that you have attempted"
+ " to use a chat completion model in a"
+ " text completion service. Try using a"
+ " chat completion service instead when"
+ " building your kernel, for instance when"
+ " building your service use"
+ " SKBuilders.chatCompletion() rather than"
+ " SKBuilders.textCompletionService().");
}
});
}
private Mono<FunctionResult> performCompletionRequest(
TextCompletion client, CompletionRequestSettings requestSettings, String prompt, boolean streaming) {
LOGGER.info("RENDERED PROMPT: \n{}", prompt);
if (streaming) {
Flux<String> completionStream = client.completeStreamAsync(prompt, requestSettings);
return Mono.just(new SemanticFunctionResult(pluginName, name, completionStream.reduce(String::concat), completionStream));
} else {
Mono<String> completion = client.completeAsync(prompt, requestSettings)
.map(list -> list.isEmpty() ? null : list.get(0));
return Mono.just(new SemanticFunctionResult(pluginName, name, completion));
}
}
@Nullable
@Override
public FunctionView describe() {
return null;
}
@Override
protected Mono<SKContext> invokeAsyncInternal(SKContext context, @Nullable Object settings) {
return null;
}
@Override
public void registerOnKernel(Kernel kernel) {
}
public static class Builder implements Buildable {
private String name;
private String pluginName;
private String description;
private List<SemanticFunctionModel.ExecutionSettingsModel> executionSettings;
private PromptTemplate promptTemplate;
private List<SemanticFunctionModel.VariableViewModel> inputParameters;
public Builder withName(String name) {
this.name = name;
return this;
}
public Builder withPluginName(String pluginName) {
this.pluginName = pluginName;
return this;
}
public Builder withDescription(String description) {
this.description = description;
return this;
}
public Builder withExecutionSettings(
List<SemanticFunctionModel.ExecutionSettingsModel> executionSettings) {
this.executionSettings = executionSettings;
return this;
}
public Builder withPromptTemplate(PromptTemplate promptTemplate) {
this.promptTemplate = promptTemplate;
return this;
}
public Builder withInputParameters(
List<SemanticFunctionModel.VariableViewModel> inputParameters) {
this.inputParameters = inputParameters;
return this;
}
public SemanticFunction build() {
return new SemanticFunction(
name,
pluginName,
description,
executionSettings,
promptTemplate,
inputParameters);
}
}
}
@@ -0,0 +1,255 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.semanticfunctions;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SemanticFunctionModel {
@JsonProperty("name")
private String name;
@JsonProperty("template")
private String template;
@JsonProperty("template_format")
private String templateFormat;
@JsonProperty("description")
private String description;
@JsonProperty("input_variables")
private List<VariableViewModel> inputVariables;
@JsonProperty("output_variable")
private VariableViewModel outputVariable;
@JsonProperty("execution_settings")
private List<ExecutionSettingsModel> executionSettings;
public SemanticFunctionModel() {}
public SemanticFunctionModel(
String name,
String template,
String templateFormat,
String description,
List<VariableViewModel> inputVariables,
VariableViewModel outputVariable,
List<ExecutionSettingsModel> executionSettings) {
this.name = name;
this.template = template;
this.templateFormat = templateFormat;
this.description = description;
this.inputVariables = inputVariables;
this.outputVariable = outputVariable;
this.executionSettings = executionSettings;
}
public static class VariableViewModel {
@JsonProperty("name")
private String name;
@JsonProperty("type")
private String type;
@JsonProperty("description")
private String description;
@JsonProperty("default_value")
private Object defaultValue;
@JsonProperty("is_required")
private boolean isRequired;
public VariableViewModel() {}
public VariableViewModel(
String name,
String type,
String description,
Object defaultValue,
boolean isRequired) {
this.name = name;
this.type = type;
this.description = description;
this.defaultValue = defaultValue;
this.isRequired = isRequired;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Object getDefaultValue() {
return defaultValue;
}
public void setDefaultValue(Object defaultValue) {
this.defaultValue = defaultValue;
}
public boolean isRequired() {
return isRequired;
}
public void setRequired(boolean required) {
isRequired = required;
}
}
public static class ExecutionSettingsModel {
@JsonProperty("model_id")
private String modelId;
@JsonProperty("model_id_pattern")
private String modelIdPattern;
@JsonProperty("service_id")
private String serviceId;
@JsonProperty("temperature")
private String temperature;
@JsonProperty("additional_properties")
private final Map<String, Object> additionalProperties;
public Object get(String propertyName) {
return additionalProperties.get(propertyName);
}
public void set(String propertyName, Object value) {
additionalProperties.put(propertyName, value);
}
public ExecutionSettingsModel() {
this.additionalProperties = new HashMap<>();
}
public ExecutionSettingsModel(
String modelId,
String modelIdPattern,
String serviceId,
String temperature,
Map<String, Object> additionalProperties) {
this.modelId = modelId;
this.modelIdPattern = modelIdPattern;
this.serviceId = serviceId;
this.temperature = temperature;
this.additionalProperties = additionalProperties;
}
public String getModelId() {
return modelId;
}
public void setModelId(String modelId) {
this.modelId = modelId;
}
public String getModelIdPattern() {
return modelIdPattern;
}
public void setModelIdPattern(String modelIdPattern) {
this.modelIdPattern = modelIdPattern;
}
public String getServiceId() {
return serviceId;
}
public void setServiceId(String serviceId) {
this.serviceId = serviceId;
}
public String getTemperature() {
return temperature;
}
public void setTemperature(String temperature) {
this.temperature = temperature;
}
public Map<String, Object> getAdditionalProperties() {
return additionalProperties;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTemplate() {
return template;
}
public void setTemplate(String template) {
this.template = template;
}
public String getTemplateFormat() {
return templateFormat;
}
public void setTemplateFormat(String templateFormat) {
this.templateFormat = templateFormat;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<VariableViewModel> getInputVariables() {
return inputVariables;
}
public void setInputVariables(List<VariableViewModel> inputVariables) {
this.inputVariables = inputVariables;
}
public VariableViewModel getOutputVariable() {
return outputVariable;
}
public void setOutputVariable(VariableViewModel outputVariable) {
this.outputVariable = outputVariable;
}
public List<ExecutionSettingsModel> getExecutionSettings() {
return executionSettings;
}
public void setExecutionSettings(List<ExecutionSettingsModel> executionSettings) {
this.executionSettings = executionSettings;
}
}
@@ -75,14 +75,13 @@ public class DefaultSkillCollection implements ReadOnlySkillCollection {
@Override
@Nullable
public <T extends SKFunction<?>> T getFunction(
String funName, @Nullable Class<T> functionClazz) {
public <T extends SKFunction> T getFunction(String funName, @Nullable Class<T> functionClazz) {
return getFunction(GlobalSkill, funName, functionClazz);
}
@Override
@Nullable
public <T extends SKFunction<?>> T getFunction(
public <T extends SKFunction> T getFunction(
String skillName, String funName, @Nullable Class<T> functionClazz) {
FunctionCollection skills = skillCollection.get(skillName.toLowerCase(Locale.ROOT));
if (skills == null) {
@@ -15,16 +15,16 @@ import javax.annotation.Nullable;
/** A collection of functions. */
public class FunctionCollection implements ReadOnlyFunctionCollection {
private final CaseInsensitiveMap<SKFunction<?>> functionCollection;
private final CaseInsensitiveMap<SKFunction> functionCollection;
private final String skillName;
private FunctionCollection(String skillName, Map<String, SKFunction<?>> functionCollection) {
private FunctionCollection(String skillName, Map<String, SKFunction> functionCollection) {
this.functionCollection = new CaseInsensitiveMap<>(functionCollection);
this.skillName = skillName;
}
public FunctionCollection(String skillName, List<? extends SKFunction<?>> functionCollection) {
public FunctionCollection(String skillName, List<? extends SKFunction> functionCollection) {
this(
skillName,
functionCollection.stream()
@@ -41,7 +41,7 @@ public class FunctionCollection implements ReadOnlyFunctionCollection {
public FunctionCollection(ReadOnlyFunctionCollection value) {
this.skillName = value.getSkillName();
this.functionCollection =
new CaseInsensitiveMap<SKFunction<?>>(
new CaseInsensitiveMap<SKFunction>(
Collections.unmodifiableMap(
value.getAll().stream()
.collect(Collectors.toMap(SKFunction::getName, it -> it))));
@@ -53,8 +53,8 @@ public class FunctionCollection implements ReadOnlyFunctionCollection {
}
@Override
public SKFunction<?> getFunction(String functionName) {
SKFunction<?> func = functionCollection.get(functionName.toLowerCase(Locale.ROOT));
public SKFunction getFunction(String functionName) {
SKFunction func = functionCollection.get(functionName.toLowerCase(Locale.ROOT));
if (func == null) {
throw new FunctionNotFound(
FunctionNotFound.ErrorCodes.FUNCTION_NOT_FOUND, functionName);
@@ -73,7 +73,7 @@ public class FunctionCollection implements ReadOnlyFunctionCollection {
*/
@Override
public <T extends SKFunction> T getFunction(String functionName, @Nullable Class<T> clazz) {
SKFunction<?> func = getFunction(functionName);
SKFunction func = getFunction(functionName);
if (clazz == null) {
return (T) func;
}
@@ -102,7 +102,7 @@ public class FunctionCollection implements ReadOnlyFunctionCollection {
* @return An unmodifiable list of all functions
*/
@Override
public List<SKFunction<?>> getAll() {
public List<SKFunction> getAll() {
return Collections.unmodifiableList(new ArrayList<>(functionCollection.values()));
}
@@ -113,7 +113,7 @@ public class FunctionCollection implements ReadOnlyFunctionCollection {
* @param functionInstance
* @return Collection for fluent callse
*/
public FunctionCollection put(String functionName, SKFunction<?> functionInstance) {
public FunctionCollection put(String functionName, SKFunction functionInstance) {
this.functionCollection.put(functionName.toLowerCase(Locale.ROOT), functionInstance);
return this;
}
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.templateengine;
import com.microsoft.semantickernel.orchestration.ContextVariables;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.templateengine.blocks.Block;
import com.microsoft.semantickernel.templateengine.blocks.CodeRendering;
@@ -62,6 +63,12 @@ public class DefaultPromptTemplateEngine implements PromptTemplateEngine {
return this.renderAsync(blocks, context);
}
@Override
public Mono<String> renderAsync(String templateText, ContextVariables variables) {
// TODO
return null;
}
/// <inheritdoc/>
public Mono<String> renderAsync(List<Block> blocks, SKContext context) {
return Flux.fromIterable(blocks)
@@ -107,9 +107,10 @@ public final class CodeBlock extends Block implements CodeRendering {
function.invokeWithCustomInputAsync(
variables, context.getSemanticMemory(), context.getSkills());
// TODO: 1.0 fix cast
return result.map(
it -> {
return it.getResult();
return (String) it.getResult();
});
}
@@ -120,7 +121,7 @@ public final class CodeBlock extends Block implements CodeRendering {
// Function in the global skill
if ((skillName == null || skillName.isEmpty())
&& skills.hasFunction(fBlock.getFunctionName())) {
SKFunction<?> function = skills.getFunction(fBlock.getFunctionName(), SKFunction.class);
SKFunction function = skills.getFunction(fBlock.getFunctionName(), SKFunction.class);
return function;
}
@@ -33,7 +33,8 @@ public final class VarBlock extends Block implements TextRendering {
"Variable rendering failed, the variable name is empty");
}
String value = variables.asMap().get(name);
// TODO: 1.0 fix cast
String value = (String) variables.asMap().get(name);
if (value == null) {
@@ -0,0 +1,35 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.templateengine.handlebars;
import com.microsoft.semantickernel.orchestration.ContextVariables;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.semanticfunctions.PromptTemplate;
import com.microsoft.semantickernel.skilldefinition.ParameterView;
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
import java.util.List;
import reactor.core.publisher.Mono;
public class HandlebarsPromptTemplate implements PromptTemplate {
private String promptTemplate;
private HandlebarsPromptTemplateEngine templateEngine;
public HandlebarsPromptTemplate(String promptTemplate, PromptTemplateEngine templateEngine) {
this.promptTemplate = promptTemplate;
this.templateEngine = (HandlebarsPromptTemplateEngine) templateEngine;
}
@Override
public List<ParameterView> getParameters() {
return null;
}
@Override
public Mono<String> renderAsync(SKContext skContext) {
return null;
}
@Override
public Mono<String> renderAsync(ContextVariables variables) {
return templateEngine.renderAsync(this.promptTemplate, variables);
}
}
@@ -0,0 +1,89 @@
// Copyright (c) Microsoft. All rights reserved.
package com.microsoft.semantickernel.templateengine.handlebars;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.jknack.handlebars.Context;
import com.github.jknack.handlebars.Handlebars;
import com.github.jknack.handlebars.Helper;
import com.github.jknack.handlebars.Options;
import com.microsoft.semantickernel.chatcompletion.ChatHistory;
import com.microsoft.semantickernel.orchestration.ContextVariables;
import com.microsoft.semantickernel.orchestration.SKContext;
import com.microsoft.semantickernel.templateengine.PromptTemplateEngine;
import com.microsoft.semantickernel.templateengine.blocks.Block;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import reactor.core.publisher.Mono;
public class HandlebarsPromptTemplateEngine implements PromptTemplateEngine {
@Override
public Mono<String> renderAsync(String s, SKContext skContext) {
throw new RuntimeException("SKContext not supported");
}
@Override
public List<Block> extractBlocks(String s) {
return null;
}
@Override
public Mono<String> renderAsync(String promptTemplate, ContextVariables variables) {
HandleBarsPromptTemplateHandler handler =
new HandleBarsPromptTemplateHandler(promptTemplate);
return handler.render(variables);
}
public static class HandleBarsPromptTemplateHandler {
private final String template;
private final Handlebars handlebars;
public HandleBarsPromptTemplateHandler(String template) {
this.template = template;
this.handlebars = new Handlebars();
this.handlebars.registerHelper(
"message",
new Helper<Object>() {
@Override
public Object apply(Object context, Options options) throws IOException {
String role = options.hash("role");
String content = (String) options.fn(context);
// when message is inside a loop Context is Optional<ChatHistory.Message>
// when message is not inside a loop Context is the UnmodifiableMap<String, Object> with all the variables
if (context instanceof Optional) {
ChatHistory.Message message = ((Optional<ChatHistory.Message>) context).orElse(null);
if (role == null || role.isEmpty()) {
role = message.getAuthorRoles()
.toString()
.toLowerCase();
}
content = message.getContent();
}
if (role != null && !role.isEmpty()) {
return new Handlebars.SafeString(
String.format(
"<message role=\"%s\">%s</message>",
role, content));
}
return "";
}
});
// TODO: 1.0 Add more helpers
}
public Mono<String> render(ContextVariables variables) {
try {
String result = handlebars.compileInline(template).apply(variables.asMap());
return Mono.just(result);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
@@ -48,8 +48,8 @@ public class NativeSKFunctionTest {
FunctionCollection skills =
SkillImporter.importSkill(skill, "test", DefaultSkillCollection::new);
ContextVariables variables = SKBuilders.variables().build();
variables = variables.writableClone().appendToVariable("input", "foo");
variables = variables.writableClone().appendToVariable("secondInput", "ignore");
variables = variables.writableClone().setVariable("input", "foo");
variables = variables.writableClone().setVariable("secondInput", "ignore");
skills.getFunction("doSomething").invokeWithCustomInputAsync(variables, null, null).block();
Mockito.verify(skill, Mockito.times(1)).doSomething("foo", "ignore");
}
@@ -68,8 +68,8 @@ public class NativeSKFunctionTest {
FunctionCollection skills =
SkillImporter.importSkill(skill, "test", DefaultSkillCollection::new);
ContextVariables variables = SKBuilders.variables().build();
variables = variables.writableClone().appendToVariable("anInput", "foo");
variables = variables.writableClone().appendToVariable("secondInput", "ignore");
variables = variables.writableClone().setVariable("anInput", "foo");
variables = variables.writableClone().setVariable("secondInput", "ignore");
skills.getFunction("doSomething").invokeWithCustomInputAsync(variables, null, null).block();
Mockito.verify(skill, Mockito.times(1)).doSomething("foo", "ignore");
}
@@ -86,7 +86,7 @@ public class NativeSKFunctionTest {
FunctionCollection skills =
SkillImporter.importSkill(skill, "test", DefaultSkillCollection::new);
ContextVariables variables =
SKBuilders.variables().build().writableClone().appendToVariable("input", "foo");
SKBuilders.variables().build().writableClone().setVariable("input", "foo");
Assertions.assertThrows(
AIException.class,
() -> {