diff --git a/java/connectors/semantickernel-connectors-ai-openai/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/chatcompletion/OpenAIChatCompletion.java b/java/connectors/semantickernel-connectors-ai-openai/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/chatcompletion/OpenAIChatCompletion.java index acd6085407..66269dfb9c 100644 --- a/java/connectors/semantickernel-connectors-ai-openai/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/chatcompletion/OpenAIChatCompletion.java +++ b/java/connectors/semantickernel-connectors-ai-openai/src/main/java/com/microsoft/semantickernel/connectors/ai/openai/chatcompletion/OpenAIChatCompletion.java @@ -184,6 +184,11 @@ public class OpenAIChatCompletion extends ClientBase implements ChatCompletion generateMessageStream( OpenAIChatHistory chat, @Nullable ChatRequestSettings requestSettings) { @@ -237,11 +242,10 @@ public class OpenAIChatCompletion extends ClientBase implements ChatCompletion { +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 { // Outputs for the plan, used to pass information to the caller private List 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 { } public Plan( - SKFunction function, + SKFunction function, ContextVariables state, List functionOutputs, KernelSkillsSupplier kernelSkillsSupplier) { @@ -88,7 +88,7 @@ public class Plan extends AbstractSkFunction { } public Plan( - SKFunction function, + SKFunction function, @Nullable ContextVariables parameters, ContextVariables state, List functionOutputs, @@ -111,13 +111,13 @@ public class Plan extends AbstractSkFunction { } public Plan( - SKFunction function, + SKFunction function, List 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 { 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 { * * @param steps The steps to add to the current plan. */ - public void addSteps(SKFunction... steps) { + public void addSteps(SKFunction... steps) { List plans = Arrays.stream(steps) .map(step -> new Plan(step, getSkillsSupplier())) diff --git a/java/extensions/semantickernel-planners/src/main/java/com/microsoft/semantickernel/planner/sequentialplanner/DefaultSequentialPlannerSKContext.java b/java/extensions/semantickernel-planners/src/main/java/com/microsoft/semantickernel/planner/sequentialplanner/DefaultSequentialPlannerSKContext.java index 20f94314da..6476b419ff 100644 --- a/java/extensions/semantickernel-planners/src/main/java/com/microsoft/semantickernel/planner/sequentialplanner/DefaultSequentialPlannerSKContext.java +++ b/java/extensions/semantickernel-planners/src/main/java/com/microsoft/semantickernel/planner/sequentialplanner/DefaultSequentialPlannerSKContext.java @@ -47,8 +47,7 @@ public class DefaultSequentialPlannerSKContext { config = new SequentialPlannerRequestSettings(); } - Mono>> functions = - getAvailableFunctionsAsync(config, semanticQuery); + Mono> functions = getAvailableFunctionsAsync(config, semanticQuery); return functions.map( funcs -> @@ -67,7 +66,7 @@ public class DefaultSequentialPlannerSKContext { // functions /// A list of functions that are available to the user based on the semantic query and // the excluded skills and functions. - public Mono>> getAvailableFunctionsAsync( + public Mono> getAvailableFunctionsAsync( SequentialPlannerRequestSettings config, @Nullable String semanticQuery) { Set excludedSkills = config.getExcludedSkills(); Set excludedFunctions = config.getExcludedFunctions(); @@ -76,14 +75,14 @@ public class DefaultSequentialPlannerSKContext { // context.ThrowIfSkillCollectionNotSet(); ReadOnlySkillCollection skills = delegate.getSkills(); - List> functions; + List functions; if (skills != null) { functions = skills.getAllFunctions().getAll(); } else { functions = Collections.emptyList(); } - List> availableFunctions = + List 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> comparator = - Comparator., String>comparing(SKFunction::getSkillName) + Comparator comparator = + Comparator.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> result = new TreeSet<>(comparator); + TreeSet 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>()); + return Mono.just(new ArrayList()); } // Search for functions that match the semantic query. return updatedMemory @@ -143,26 +142,26 @@ public class DefaultSequentialPlannerSKContext { .map(SKFunction::getName) .collect(Collectors.toList()); - List> missingFunctions = + List missingFunctions = getMissingFunctions( includedFunctions, availableFunctions, added); - ArrayList> res = new ArrayList<>(memories); + ArrayList res = new ArrayList<>(memories); res.addAll(missingFunctions); return res; }) .map( res -> { - TreeSet> result = new TreeSet<>(comparator); + TreeSet result = new TreeSet<>(comparator); result.addAll(availableFunctions); return result; }); } } - private static List> getMissingFunctions( + private static List getMissingFunctions( Set includedFunctions, - List> availableFunctions, + List availableFunctions, List added) { return includedFunctions.stream() .filter(func -> !added.contains(func)) @@ -173,8 +172,8 @@ public class DefaultSequentialPlannerSKContext { .collect(Collectors.toList()); } - public Mono>> getRelevantFunctionsAsync( - List> availableFunctions, List memories) { + public Mono> getRelevantFunctionsAsync( + List availableFunctions, List memories) { return Flux.fromIterable(memories) .map( memoryEntry -> @@ -195,7 +194,7 @@ public class DefaultSequentialPlannerSKContext { /// /// The SKContext to save the functions to. /// The available functions to save. - Mono rememberFunctionsAsync(List> availableFunctions) { + Mono rememberFunctionsAsync(List availableFunctions) { // Check if the functions have already been saved to memory. if (delegate.getVariables().asMap().containsKey(PlanSKFunctionsAreRemembered)) { return Mono.just(delegate); diff --git a/java/extensions/semantickernel-planners/src/main/java/com/microsoft/semantickernel/planner/stepwiseplanner/DefaultStepwisePlanner.java b/java/extensions/semantickernel-planners/src/main/java/com/microsoft/semantickernel/planner/stepwiseplanner/DefaultStepwisePlanner.java index ec7cfd0c57..7aa300b5d0 100644 --- a/java/extensions/semantickernel-planners/src/main/java/com/microsoft/semantickernel/planner/stepwiseplanner/DefaultStepwisePlanner.java +++ b/java/extensions/semantickernel-planners/src/main/java/com/microsoft/semantickernel/planner/stepwiseplanner/DefaultStepwisePlanner.java @@ -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 invokeActionAsync(String actionName, Map actionVariables) { - List> availableFunctions = this.getAvailableFunctions(); - Optional> targetFunction = + List availableFunctions = this.getAvailableFunctions(); + Optional 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> getAvailableFunctions() { + private List 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., String>comparing( - SKFunction::getSkillName) + Comparator.comparing(SKFunction::getSkillName) .thenComparing(SKFunction::getName) .compare(a, b)) .collect(Collectors.toList()); } private String getFunctionDescriptions() { - List> availableFunctions = this.getAvailableFunctions(); + List availableFunctions = this.getAvailableFunctions(); return availableFunctions.stream() .map(x -> toManualString(Objects.requireNonNull(x.describe()))) .collect(Collectors.joining("\n")); } - private SKFunction importStepwiseFunction( + private SKFunction importStepwiseFunction( Kernel kernel, String promptTemplate, PromptTemplateConfig config) { PromptTemplate template = SKBuilders.promptTemplate() diff --git a/java/plugins/semantickernel-plugin-core/src/main/java/com/microsoft/semantickernel/coreskills/TextMemorySkill.java b/java/plugins/semantickernel-plugin-core/src/main/java/com/microsoft/semantickernel/coreskills/TextMemorySkill.java index 3abc41791a..52c3a84cc2 100644 --- a/java/plugins/semantickernel-plugin-core/src/main/java/com/microsoft/semantickernel/coreskills/TextMemorySkill.java +++ b/java/plugins/semantickernel-plugin-core/src/main/java/com/microsoft/semantickernel/coreskills/TextMemorySkill.java @@ -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; diff --git a/java/pom.xml b/java/pom.xml index 7ca29db60d..2898acb381 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -64,22 +64,22 @@ - connectors/semantickernel-connectors-memory-azurecognitivesearch - connectors/semantickernel-connectors-memory-jdbc - connectors/semantickernel-connectors-memory-postgresql - connectors/semantickernel-connectors-memory-mysql --> + + + - extensions/semantickernel-gpt3-tokenizer - extensions/semantickernel-settings-loader --> + extensions/semantickernel-settings-loader - + plugins/semantickernel-plugin-core semantickernel-bom semantickernel-api - + semantickernel-core @@ -717,13 +717,13 @@ - - with-samples - - samples - api-test - - + + + + + + + release diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/Kernel.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/Kernel.java index 106b303871..211e735c55 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/Kernel.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/Kernel.java @@ -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/Mono/ + * @apiNote Breaking change: s/SKFunction/SKFunction/, s/Mono/Mono/ */ @Deprecated Mono 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/Mono/ + * @apiNote Breaking change: s/SKFunction/SKFunction/, s/Mono/Mono/ */ @Deprecated Mono 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/Mono/ + * @apiNote Breaking change: s/SKFunction/SKFunction/, s/Mono/Mono/ */ Mono 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 runAsync(boolean streaming, ContextVariables variables, SKFunction... pipeline); + Mono runAsync( + boolean streaming, ContextVariables variables, SKFunction... pipeline); /** * Register a semantic function on this kernel @@ -113,15 +114,20 @@ public interface Kernel extends Buildable { T getService(@Nullable String name, Class clazz) throws KernelException; - /** Registers a semantic function on this kernel - * @apiNote Breaking change: s/>// - */ + /** + * Registers a semantic function on this kernel + * + * @apiNote Breaking change: s/// + */ @Deprecated - - FunctionType registerSemanticFunction(FunctionType semanticFunctionDefinition); + 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 { /** * 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 diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/KernelResult.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/KernelResult.java index bb41fea6f5..7ce659509e 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/KernelResult.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/KernelResult.java @@ -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 functionResults(); - } diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/chatcompletion/ChatCompletion.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/chatcompletion/ChatCompletion.java index 34ffeda011..48b88fbc0b 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/chatcompletion/ChatCompletion.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/chatcompletion/ChatCompletion.java @@ -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 createNewChat(String instructions); - /** + /** * Create a new empty chat instance * * @return Chat object @@ -44,7 +42,6 @@ public interface ChatCompletion */ ChatHistoryType createNewChat(); - Flux generateMessageStream( ChatHistoryType chatHistory, @Nullable ChatRequestSettings requestSettings); diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/chatcompletion/ChatHistory.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/chatcompletion/ChatHistory.java index f869e1cb74..8d00955e3c 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/chatcompletion/ChatHistory.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/chatcompletion/ChatHistory.java @@ -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)); } - } diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/nativefunction/NativeFunction.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/nativefunction/NativeFunction.java index d3f7afe52c..b7aab32dc3 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/nativefunction/NativeFunction.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/nativefunction/NativeFunction.java @@ -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 getFunctionsFromObject(Object object) { return null; } - } diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/AbstractSKContext.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/AbstractSKContext.java index 6fc342c717..43c445ec61 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/AbstractSKContext.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/AbstractSKContext.java @@ -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); diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/AbstractSkFunction.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/AbstractSKFunction.java similarity index 94% rename from java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/AbstractSkFunction.java rename to java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/AbstractSKFunction.java index 77d70e247a..a127cc0040 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/AbstractSkFunction.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/AbstractSKFunction.java @@ -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 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 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 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 invokeAsync( - @Nullable SKContext context, @Nullable Object settings) { + public Mono invokeAsync(@Nullable SKContext context, @Nullable Object settings) { if (context == null) { context = SKBuilders.context() diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/ContextVariables.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/ContextVariables.java index 6afbc67b56..d03265957e 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/ContextVariables.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/ContextVariables.java @@ -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 diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionResult.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionResult.java index 39e9e2e934..01ef87d3cb 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionResult.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionResult.java @@ -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 metadata(); /** * Get the function result. + * * @return The function result. - * @param The type of the function result. */ - Mono getValueAsync(); + Mono getValueAsync(); /** * Get the function result. + * * @return The function result. - * @param The type of the function result. */ - Flux getStreamingValueAsync(); + Flux getStreamingValueAsync(); /** * Get the function result. + * * @return The function result. - * @param The type of the function result. */ - T getValue(); - + String getValue(); /** * Get typed data from metadata. diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/SKContext.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/SKContext.java index 6afd25e604..3b9280304f 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/SKContext.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/SKContext.java @@ -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. diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/SKFunction.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/SKFunction.java index 29fd2d3ff3..99f91c60be 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/SKFunction.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/SKFunction.java @@ -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/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 getType(); + * @return The type @Nullable Class getType(); */ /** @@ -70,8 +66,26 @@ public interface SKFunction { * @return an updated context with the result of the request */ @CheckReturnValue + @Deprecated Mono invokeAsync(SKContext context); + /** + * The type of the configuration argument that will be provided when the function is invoked + * + * @return The type @Nullable Class 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 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 invokeAsync(SKContext context, @Nullable Object settings); + Mono 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 invokeAsync(Kernel kernel, Map variables); - /** * @return The name of the skill that this function is within */ diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/WritableContextVariables.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/WritableContextVariables.java index fb92731c92..a7cfc50539 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/WritableContextVariables.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/WritableContextVariables.java @@ -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. * diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/Plugin.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/Plugin.java index 21493b2731..5ab6b1910f 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/Plugin.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/Plugin.java @@ -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(); diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplate.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplate.java index 5e4cf5181e..3fc378c416 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplate.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/semanticfunctions/PromptTemplate.java @@ -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 renderAsync(SKContext executionContext); + Mono renderAsync(ContextVariables variables); + static Builder builder() { return BuildersSingleton.INST.getInstance(Builder.class); } diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/skilldefinition/KernelSkillsSupplier.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/skilldefinition/KernelSkillsSupplier.java index 691765dec1..9810f60f32 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/skilldefinition/KernelSkillsSupplier.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/skilldefinition/KernelSkillsSupplier.java @@ -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 { @Deprecated static KernelSkillsSupplier getInstance(Kernel kernel) { - return null; //kernel::getSkills; + return null; // kernel::getSkills; } } diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/skilldefinition/ReadOnlyFunctionCollection.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/skilldefinition/ReadOnlyFunctionCollection.java index 05d565d224..65ea69e845 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/skilldefinition/ReadOnlyFunctionCollection.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/skilldefinition/ReadOnlyFunctionCollection.java @@ -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(); diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/skilldefinition/ReadOnlySkillCollection.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/skilldefinition/ReadOnlySkillCollection.java index 7214199cb0..b064790e89 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/skilldefinition/ReadOnlySkillCollection.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/skilldefinition/ReadOnlySkillCollection.java @@ -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 diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/PromptTemplateEngine.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/PromptTemplateEngine.java index 77c8054ddd..84bbf6cdb9 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/PromptTemplateEngine.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/PromptTemplateEngine.java @@ -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 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 renderAsync(String templateText, ContextVariables variables); + /** * Given a prompt template string, extract all the blocks (text, variables, function calls) * diff --git a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/textcompletion/CompletionSKFunction.java b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/textcompletion/CompletionSKFunction.java index 91f81b7546..f5abee0f08 100644 --- a/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/textcompletion/CompletionSKFunction.java +++ b/java/semantickernel-api/src/main/java/com/microsoft/semantickernel/textcompletion/CompletionSKFunction.java @@ -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 */ diff --git a/java/semantickernel-core/pom.xml b/java/semantickernel-core/pom.xml index 2f317d6b63..d6e89600bf 100644 --- a/java/semantickernel-core/pom.xml +++ b/java/semantickernel-core/pom.xml @@ -81,15 +81,41 @@ semantickernel-plugin-core test - - com.microsoft.semantic-kernel - semantickernel-planners - test - + + + + + jakarta.inject jakarta.inject-api + + + + com.github.jknack + handlebars + 4.3.1 + + + + com.fasterxml.jackson.core + jackson-core + 2.15.2 + compile + + + com.fasterxml.jackson.core + jackson-databind + 2.15.2 + compile + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + 2.15.2 + + \ No newline at end of file diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/DefaultKernel.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/DefaultKernel.java index 21c38589e6..0f17ebdf77 100644 --- a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/DefaultKernel.java +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/DefaultKernel.java @@ -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 registerSemanticFunction( + FunctionType semanticFunctionDefinition) { + return null; + } + @Override public KernelConfig getConfig() { return kernelConfig; } - @Override - public > - 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 + // 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. /// A list of all the semantic functions found in the directory, indexed by function // name. - @Override - public ReadOnlyFunctionCollection importSkill( - String skillName, Map 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(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 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(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 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 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 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 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 runAsync(SKFunction... pipeline) { + public Mono runAsync(SKFunction... pipeline) { return runAsync(SKBuilders.variables().build(), pipeline); } @Override - public Mono runAsync(String input, SKFunction... pipeline) { + public Mono runAsync(String input, SKFunction... pipeline) { return runAsync(SKBuilders.variables().withInput(input).build(), pipeline); } @Override - public Mono runAsync(ContextVariables variables, SKFunction... pipeline) { + public Mono runAsync(ContextVariables variables, SKFunction... pipeline) { + return null; + } + + @Override + public Mono 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 pipelineBuilder = - Mono.just( - SKBuilders.context() - .withVariables(variables) - .withSkills(getSkills()) - .build()); + List> 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 * diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/DefaultKernelResult.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/DefaultKernelResult.java new file mode 100644 index 0000000000..3f6f1c730f --- /dev/null +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/DefaultKernelResult.java @@ -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 results; + + public DefaultKernelResult(Collection results) { + this.results = results; + } + + @Override + public Collection functionResults() { + return this.results; + } +} diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/functions/SemanticFunctionResult.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/functions/SemanticFunctionResult.java new file mode 100644 index 0000000000..8e95704e78 --- /dev/null +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/functions/SemanticFunctionResult.java @@ -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 valueAsync; + private Flux streamingValueAsync; + private boolean isStreaming; + private String functionName; + private String pluginName; + private Map metadata; + + public SemanticFunctionResult() {} + + public SemanticFunctionResult(String pluginName, String functionName, Mono valueAsync) { + this.valueAsync = valueAsync; + this.pluginName = pluginName; + this.functionName = functionName; + this.isStreaming = false; + } + + public SemanticFunctionResult(String pluginName, String functionName, Mono valueAsync, Flux 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 metadata() { + return null; + } + + @Override + public Flux getStreamingValueAsync() { + return streamingValueAsync; + } + + @Override + public Mono getValueAsync() { + return valueAsync; + } + + @Override + public String getValue() { + return valueAsync.block(); + } +} diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultCompletionSKFunction.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultCompletionSKFunction.java index b282d892f5..15412dfa8e 100644 --- a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultCompletionSKFunction.java +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultCompletionSKFunction.java @@ -32,8 +32,7 @@ import reactor.core.publisher.Mono; // cref="Action"/>, /// with additional methods required by the kernel. /// -public class DefaultCompletionSKFunction - extends DefaultSemanticSKFunction +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 invokeAsyncInternal( - SKContext context, @Nullable CompletionRequestSettings settings) { + protected Mono 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 getType() { - return CompletionRequestSettings.class; - } - private static String randomFunctionName() { return "func" + UUID.randomUUID(); } @@ -277,6 +272,11 @@ public class DefaultCompletionSKFunction false); } + @Override + public Mono invokeAsync(Kernel kernel, ContextVariables variables, boolean streaming) { + return null; + } + public static class Builder implements CompletionSKFunction.Builder { private Kernel kernel; diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultContextVariables.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultContextVariables.java index 2b931ff857..7cdf591786 100644 --- a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultContextVariables.java +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultContextVariables.java @@ -13,7 +13,7 @@ import reactor.util.annotation.NonNull; /// class DefaultContextVariables implements ContextVariables, WritableContextVariables { - private final CaseInsensitiveMap variables; + private final CaseInsensitiveMap variables; /// /// 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. /// /// Optional value for the main variable of the context. - DefaultContextVariables(@NonNull String content) { + DefaultContextVariables(@NonNull Object content) { this.variables = new CaseInsensitiveMap<>(); this.variables.put(MAIN_KEY, content); } - DefaultContextVariables(Map variables) { + DefaultContextVariables(Map 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 asMap() { + public Map asMap() { return Collections.unmodifiableMap(variables); } @@ -66,7 +52,7 @@ class DefaultContextVariables implements ContextVariables, WritableContextVariab /// if the pipeline reached the end. /// The current instance @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 /// Whether to merge and keep old data, or replace. False == discard old // data. /// The current instance - @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 map) { + public WritableContextVariables build(Map map) { return new DefaultContextVariables(map); } } public static class Builder implements ContextVariables.Builder { - private final Map variables; + private final Map 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 map) { + public Builder withVariables(Map map) { variables.putAll(map); return this; } diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultSKContext.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultSKContext.java index c078264ab1..086e03a8d6 100644 --- a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultSKContext.java +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultSKContext.java @@ -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; diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultSemanticSKFunction.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultSemanticSKFunction.java index 7f032198cf..a06b0ab8b8 100644 --- a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultSemanticSKFunction.java +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/DefaultSemanticSKFunction.java @@ -16,9 +16,7 @@ import reactor.core.publisher.Mono; // cref="Action"/>, /// with additional methods required by the kernel. /// -public abstract class DefaultSemanticSKFunction - extends AbstractSkFunction - implements SKFunction { +public abstract class DefaultSemanticSKFunction extends AbstractSKFunction implements SKFunction { public DefaultSemanticSKFunction( List parameters, @@ -37,9 +35,7 @@ public abstract class DefaultSemanticSKFunction @Override public Mono invokeAsync( - @Nullable String input, - @Nullable SKContext context, - @Nullable RequestConfiguration settings) { + @Nullable String input, @Nullable SKContext context, @Nullable Object settings) { if (context == null) { assertSkillSupplierRegistered(); context = diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/NativeSKFunction.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/NativeSKFunction.java index 5c4193766e..d0b1fdf034 100644 --- a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/NativeSKFunction.java +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/orchestration/NativeSKFunction.java @@ -40,7 +40,7 @@ import reactor.core.scheduler.Schedulers; // cref="Action"/>, /// with additional methods required by the kernel. /// -public class NativeSKFunction extends AbstractSkFunction { +public class NativeSKFunction extends AbstractSKFunction { private static final Logger LOGGER = LoggerFactory.getLogger(NativeSKFunction.class); @@ -76,8 +76,8 @@ public class NativeSKFunction extends AbstractSkFunction { } @Override - public Class getType() { - return Void.class; + public Mono invokeAsync(Kernel kernel, ContextVariables variables, boolean streaming) { + return null; } @Override @@ -152,7 +152,7 @@ public class NativeSKFunction extends AbstractSkFunction { // Run the native function @Override - protected Mono invokeAsyncInternal(SKContext context, @Nullable Void settings) { + protected Mono invokeAsyncInternal(SKContext context, @Nullable Object settings) { return this.function.run(context); } @@ -352,11 +352,12 @@ public class NativeSKFunction extends AbstractSkFunction { Method method, SKContext context, Parameter parameter, Set 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; } diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/semanticfunctions/DefaultPromptTemplate.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/semanticfunctions/DefaultPromptTemplate.java index 7b8ee70bcd..f8b73b40d6 100644 --- a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/semanticfunctions/DefaultPromptTemplate.java +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/semanticfunctions/DefaultPromptTemplate.java @@ -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 renderAsync(ContextVariables variables) { + return null; + } + public static final class Builder implements PromptTemplate.Builder { @Nullable private String promptTemplate = null; @Nullable private PromptTemplateConfig config = null; diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/semanticfunctions/SemanticFunction.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/semanticfunctions/SemanticFunction.java new file mode 100644 index 0000000000..d0947d570d --- /dev/null +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/semanticfunctions/SemanticFunction.java @@ -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 executionSettings; + private List inputParameters; + private PromptTemplate promptTemplate; + + public SemanticFunction( + String name, + String pluginName, + String description, + List executionSettings, + PromptTemplate promptTemplate, + List 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 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 performCompletionRequest( + TextCompletion client, CompletionRequestSettings requestSettings, String prompt, boolean streaming) { + + LOGGER.info("RENDERED PROMPT: \n{}", prompt); + + if (streaming) { + Flux completionStream = client.completeStreamAsync(prompt, requestSettings); + + return Mono.just(new SemanticFunctionResult(pluginName, name, completionStream.reduce(String::concat), completionStream)); + } else { + Mono 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 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 executionSettings; + private PromptTemplate promptTemplate; + private List 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 executionSettings) { + this.executionSettings = executionSettings; + return this; + } + + public Builder withPromptTemplate(PromptTemplate promptTemplate) { + this.promptTemplate = promptTemplate; + return this; + } + + public Builder withInputParameters( + List inputParameters) { + this.inputParameters = inputParameters; + return this; + } + + public SemanticFunction build() { + return new SemanticFunction( + name, + pluginName, + description, + executionSettings, + promptTemplate, + inputParameters); + } + } +} diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/semanticfunctions/SemanticFunctionModel.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/semanticfunctions/SemanticFunctionModel.java new file mode 100644 index 0000000000..d3a32467d2 --- /dev/null +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/semanticfunctions/SemanticFunctionModel.java @@ -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 inputVariables; + + @JsonProperty("output_variable") + private VariableViewModel outputVariable; + + @JsonProperty("execution_settings") + private List executionSettings; + + public SemanticFunctionModel() {} + + public SemanticFunctionModel( + String name, + String template, + String templateFormat, + String description, + List inputVariables, + VariableViewModel outputVariable, + List 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 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 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 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 getInputVariables() { + return inputVariables; + } + + public void setInputVariables(List inputVariables) { + this.inputVariables = inputVariables; + } + + public VariableViewModel getOutputVariable() { + return outputVariable; + } + + public void setOutputVariable(VariableViewModel outputVariable) { + this.outputVariable = outputVariable; + } + + public List getExecutionSettings() { + return executionSettings; + } + + public void setExecutionSettings(List executionSettings) { + this.executionSettings = executionSettings; + } +} diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/skilldefinition/DefaultSkillCollection.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/skilldefinition/DefaultSkillCollection.java index a88bc5aa57..b2cadaf26f 100644 --- a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/skilldefinition/DefaultSkillCollection.java +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/skilldefinition/DefaultSkillCollection.java @@ -75,14 +75,13 @@ public class DefaultSkillCollection implements ReadOnlySkillCollection { @Override @Nullable - public > T getFunction( - String funName, @Nullable Class functionClazz) { + public T getFunction(String funName, @Nullable Class functionClazz) { return getFunction(GlobalSkill, funName, functionClazz); } @Override @Nullable - public > T getFunction( + public T getFunction( String skillName, String funName, @Nullable Class functionClazz) { FunctionCollection skills = skillCollection.get(skillName.toLowerCase(Locale.ROOT)); if (skills == null) { diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/skilldefinition/FunctionCollection.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/skilldefinition/FunctionCollection.java index be2ca4d78b..7a82bca4dd 100644 --- a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/skilldefinition/FunctionCollection.java +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/skilldefinition/FunctionCollection.java @@ -15,16 +15,16 @@ import javax.annotation.Nullable; /** A collection of functions. */ public class FunctionCollection implements ReadOnlyFunctionCollection { - private final CaseInsensitiveMap> functionCollection; + private final CaseInsensitiveMap functionCollection; private final String skillName; - private FunctionCollection(String skillName, Map> functionCollection) { + private FunctionCollection(String skillName, Map functionCollection) { this.functionCollection = new CaseInsensitiveMap<>(functionCollection); this.skillName = skillName; } - public FunctionCollection(String skillName, List> functionCollection) { + public FunctionCollection(String skillName, List 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>( + new CaseInsensitiveMap( 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 getFunction(String functionName, @Nullable Class 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> getAll() { + public List 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; } diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/DefaultPromptTemplateEngine.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/DefaultPromptTemplateEngine.java index 76855128b3..975cc6e348 100644 --- a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/DefaultPromptTemplateEngine.java +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/DefaultPromptTemplateEngine.java @@ -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 renderAsync(String templateText, ContextVariables variables) { + // TODO + return null; + } + /// public Mono renderAsync(List blocks, SKContext context) { return Flux.fromIterable(blocks) diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/blocks/CodeBlock.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/blocks/CodeBlock.java index 514f21750b..59895a9503 100644 --- a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/blocks/CodeBlock.java +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/blocks/CodeBlock.java @@ -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; } diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/blocks/VarBlock.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/blocks/VarBlock.java index 33d115745b..e9d94f310f 100644 --- a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/blocks/VarBlock.java +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/blocks/VarBlock.java @@ -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) { diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplate.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplate.java new file mode 100644 index 0000000000..a705926b31 --- /dev/null +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplate.java @@ -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 getParameters() { + return null; + } + + @Override + public Mono renderAsync(SKContext skContext) { + return null; + } + + @Override + public Mono renderAsync(ContextVariables variables) { + return templateEngine.renderAsync(this.promptTemplate, variables); + } +} diff --git a/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplateEngine.java b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplateEngine.java new file mode 100644 index 0000000000..7d57f58fdc --- /dev/null +++ b/java/semantickernel-core/src/main/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplateEngine.java @@ -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 renderAsync(String s, SKContext skContext) { + throw new RuntimeException("SKContext not supported"); + } + + @Override + public List extractBlocks(String s) { + return null; + } + + @Override + public Mono 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() { + @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 + // when message is not inside a loop Context is the UnmodifiableMap with all the variables + if (context instanceof Optional) { + ChatHistory.Message message = ((Optional) 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( + "%s", + role, content)); + } + return ""; + } + }); + + // TODO: 1.0 Add more helpers + } + + public Mono render(ContextVariables variables) { + try { + String result = handlebars.compileInline(template).apply(variables.asMap()); + return Mono.just(result); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/orchestration/NativeSKFunctionTest.java b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/orchestration/NativeSKFunctionTest.java index 478325baae..76dc278827 100644 --- a/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/orchestration/NativeSKFunctionTest.java +++ b/java/semantickernel-core/src/test/java/com/microsoft/semantickernel/orchestration/NativeSKFunctionTest.java @@ -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, () -> {