diff --git a/.gitignore b/.gitignore index eef1881b8..85fa5e4e2 100644 --- a/.gitignore +++ b/.gitignore @@ -487,4 +487,7 @@ $RECYCLE.BIN/ elsa.sqlite.* # env files -.env \ No newline at end of file +.env + +# ignore local elsa-core src +elsa-core/ \ No newline at end of file diff --git a/Elsa.SemanticKernel/Activities/ActivityProviders/SemanticKernelSkillActivityProvider.cs b/Elsa.SemanticKernel/Activities/ActivityProviders/SemanticKernelSkillActivityProvider.cs new file mode 100644 index 000000000..b84bbd49c --- /dev/null +++ b/Elsa.SemanticKernel/Activities/ActivityProviders/SemanticKernelSkillActivityProvider.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Elsa; +using Elsa.Expressions.Models; +using Elsa.Extensions; +using Elsa.Workflows.Core; +using Elsa.Workflows.Core.Contracts; +using Elsa.Workflows.Core.Models; +using Elsa.Workflows.Management.Extensions; +using Elsa.Workflows.Core.Attributes; +using Elsa.Workflows.Core.Models; +using Elsa.Expressions.Models; +using Elsa.Extensions; +using Elsa.Http; +using Microsoft.Extensions.Logging; +using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.Connectors.Memory.Qdrant; +using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextEmbedding; +using Microsoft.SemanticKernel.Memory; +using Microsoft.SemanticKernel.Orchestration; +using Microsoft.SemanticKernel.Reliability; +using Microsoft.SKDevTeam; + +namespace Elsa.SemanticKernel; + +// +// Loads the Semantic Kernel skills and then generates activites for each skill +// +public class SemanticKernelActivityProvider : IActivityProvider +{ + private readonly IActivityFactory _activityFactory; + private readonly IActivityDescriber _activityDescriber; + + public SemanticKernelActivityProvider(IActivityFactory activityFactory, IActivityDescriber activityDescriber) + { + _activityFactory = activityFactory; + _activityDescriber = activityDescriber; + } + public async ValueTask> GetDescriptorsAsync(CancellationToken cancellationToken = default) + { + //get a list of skills in the assembly + var skills = await LoadSkillsFromAssemblyAsync("skills"); + var descriptors = new List(); + foreach (var skill in skills) + { + //var descriptor = await CreateActivityDescriptors(skill, cancellationToken); + // descriptors.Add(descriptor); + } + return descriptors; + } + + /// + /// Gets a list of the skills in the assembly + /// + private async Task> LoadSkillsFromAssemblyAsync(string assemblyName) + { + var skills = new List(); + var assembly = Assembly.Load(assemblyName); + //IEnumerable skillTypes = GetTypesInNamespace(assembly, "skills"); + Type[] skillTypes = assembly.GetTypes().ToArray(); + foreach(Type skillType in skillTypes) + { + Console.WriteLine($"Found type: {assembly.FullName}.{skillType.Namespace}.{skillType.Name}"); + if(skillType.Namespace.Equals("Microsoft.SKDevTeam")) + { + skills.Add(skillType.Name); + + Console.WriteLine($"Added skill: {skillType.Name}"); + } + + } + return skills; + } + + + + private IEnumerable GetTypesInNamespace(Assembly assembly, string nameSpace) + { + return + assembly.GetTypes() + .Where(t => String.Equals(t.Namespace, nameSpace, StringComparison.Ordinal)); + } +} + diff --git a/Elsa.SemanticKernel/Activities/SemanticKernel.cs b/Elsa.SemanticKernel/Activities/SemanticKernel.cs index 72f08c15a..3883ffe90 100644 --- a/Elsa.SemanticKernel/Activities/SemanticKernel.cs +++ b/Elsa.SemanticKernel/Activities/SemanticKernel.cs @@ -10,11 +10,21 @@ using Microsoft.SemanticKernel.Connectors.AI.OpenAI.TextEmbedding; using Microsoft.SemanticKernel.Memory; using Microsoft.SemanticKernel.Orchestration; using Microsoft.SemanticKernel.Reliability; -namespace Elsa.SemanticKernel; +using Microsoft.SemanticKernel.SkillDefinition; +using Microsoft.SKDevTeam; + using System; -using System.Text.Json; +using System.Text; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +using System.Threading; using System.Threading.Tasks; -using skills; + + +namespace Elsa.SemanticKernel; /// /// Invoke a Semantic Kernel skill. @@ -53,11 +63,11 @@ public class SemanticKernelSkill : CodeActivity DefaultValue = "ChatCompletion")] public Input FunctionName { get; set; } -/* [Input( - Description = "Mockup - don't actually call the AI, just output the prompts", - UIHint = InputUIHints.Checkbox, - DefaultValue = false)] - public Input Mockup { get; set; } */ + /* [Input( + Description = "Mockup - don't actually call the AI, just output the prompts", + UIHint = InputUIHints.Checkbox, + DefaultValue = false)] + public Input Mockup { get; set; } */ /// protected override async ValueTask ExecuteAsync(ActivityExecutionContext workflowContext) @@ -116,20 +126,95 @@ public class SemanticKernelSkill : CodeActivity } */ var skillConfig = SemanticFunctionConfig.ForSkillAndFunction(skillName, functionName); - var function = kernel.CreateSemanticFunction(skillConfig.PromptTemplate, skillConfig.Name, skillConfig.SkillName, - skillConfig.Description, skillConfig.MaxTokens, skillConfig.Temperature, - skillConfig.TopP, skillConfig.PPenalty, skillConfig.FPenalty); - var context = new ContextVariables(); - context.Set("input", prompt); + + /* var function = kernel.CreateSemanticFunction(skillConfig.PromptTemplate, skillConfig.Name, skillConfig.SkillName, + skillConfig.Description, skillConfig.MaxTokens, skillConfig.Temperature, + skillConfig.TopP, skillConfig.PPenalty, skillConfig.FPenalty); */ + + var contextVars = new ContextVariables(); + contextVars.Set("input", prompt); + SKContext context = kernel.CreateNewContext(); + + var theSkills = LoadSkillsFromAssemblyAsync("skills", kernel); + var functionsAvailable = context.Skills.GetFunctionsView(); + + var list = new StringBuilder(); + foreach (KeyValuePair> skill in functionsAvailable.SemanticFunctions) + { + Console.WriteLine($"Skill: {skill.Key}"); + foreach (FunctionView func in skill.Value) + { + // Function description + if (func.Description != null) + { + list.AppendLine($"// {func.Description}"); + } + else + { + Console.WriteLine("{0}.{1} is missing a description", func.SkillName, func.Name); + list.AppendLine($"// Function {func.SkillName}.{func.Name}."); + } + + // Function name + list.AppendLine($"{func.SkillName}.{func.Name}"); + + // Function parameters + foreach (var p in func.Parameters) + { + var description = string.IsNullOrEmpty(p.Description) ? p.Name : p.Description; + var defaultValueString = string.IsNullOrEmpty(p.DefaultValue) ? string.Empty : $" (default value: {p.DefaultValue})"; + list.AppendLine($"Parameter \"{p.Name}\": {description} {defaultValueString}"); + } + } + } + + Console.WriteLine($"List of all skills ----- {list.ToString()}"); + //context.Set("wafContext", wafContext); - SKContext answer = await kernel.RunAsync(context, function).ConfigureAwait(false); + SKContext answer = await kernel.RunAsync(contextVars, function).ConfigureAwait(false); string result = answer.Result; - - Console.WriteLine(info); - + workflowContext.SetResult(result); } } + /// + /// Gets a list of the skills in the assembly + /// + private IEnumerable LoadSkillsFromAssemblyAsync(string assemblyName, IKernel kernel) + { + var skills = new List(); + var assembly = Assembly.Load(assemblyName); + Type[] skillTypes = assembly.GetTypes().ToArray(); + foreach (Type skillType in skillTypes) + { + if (skillType.Namespace.Equals("Microsoft.SKDevTeam")) + { + skills.Add(skillType.Name); + var functions = skillType.GetFields(); + foreach (var function in functions) + { + string field = function.FieldType.ToString(); + if (field.Equals("Microsoft.SKDevTeam.SemanticFunctionConfig")) + { + var skillConfig = SemanticFunctionConfig.ForSkillAndFunction(skillType.Name, function.Name); + var skfunc = kernel.CreateSemanticFunction( + skillConfig.PromptTemplate, + skillConfig.Name, + skillConfig.SkillName, + skillConfig.Description, + skillConfig.MaxTokens, + skillConfig.Temperature, + skillConfig.TopP, + skillConfig.PPenalty, + skillConfig.FPenalty); + + Console.WriteLine($"SK Added function: {skfunc.SkillName}.{skfunc.Name}"); + } + } + } + } + return skills; + } } \ No newline at end of file diff --git a/Elsa.SemanticKernel/Elsa.SemanticKernel.csproj b/Elsa.SemanticKernel/Elsa.SemanticKernel.csproj index c6f15a6e7..9f6e6c2ee 100644 --- a/Elsa.SemanticKernel/Elsa.SemanticKernel.csproj +++ b/Elsa.SemanticKernel/Elsa.SemanticKernel.csproj @@ -5,11 +5,15 @@ Activities for calling Semantic Kernel SDK - elsa module semantic kerne activities + elsa module semantic kernel activities - + + + + + diff --git a/WorkflowsApp/WorkflowsApp.csproj b/WorkflowsApp/WorkflowsApp.csproj index d5e4e63e7..240d57ef4 100644 --- a/WorkflowsApp/WorkflowsApp.csproj +++ b/WorkflowsApp/WorkflowsApp.csproj @@ -7,13 +7,13 @@ - - - - - - -