mirror of
https://github.com/microsoft/autogen.git
synced 2025-11-01 10:19:46 +00:00
Merge branch 'elsa3new'
This commit is contained in:
commit
81b84eceec
12
.gitignore
vendored
12
.gitignore
vendored
@ -482,3 +482,15 @@ $RECYCLE.BIN/
|
||||
|
||||
# Vim temporary swap files
|
||||
*.swp
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
# SQLite workflows DB
|
||||
elsa.sqlite.*
|
||||
|
||||
# env files
|
||||
.env
|
||||
|
||||
# ignore local elsa-core src
|
||||
elsa-core/
|
||||
>>>>>>> elsa3new
|
||||
|
||||
6
.vscode/extensions.json
vendored
Normal file
6
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"ms-azuretools.vscode-azurefunctions",
|
||||
"ms-dotnettools.csharp"
|
||||
]
|
||||
}
|
||||
11
.vscode/launch.json
vendored
Normal file
11
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Attach to .NET Functions",
|
||||
"type": "coreclr",
|
||||
"request": "attach",
|
||||
"processId": "${command:azureFunctions.pickProcess}"
|
||||
}
|
||||
]
|
||||
}
|
||||
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
@ -1,3 +1,12 @@
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
"dotnet.defaultSolution": "sk-dev-team.sln"
|
||||
=======
|
||||
"dotnet.defaultSolution": "sk-dev-team.sln",
|
||||
"azureFunctions.deploySubpath": "sk-azfunc-server/bin/Release/net7.0/publish",
|
||||
"azureFunctions.projectLanguage": "C#",
|
||||
"azureFunctions.projectRuntime": "~4",
|
||||
"debug.internalConsoleOptions": "neverOpen",
|
||||
"azureFunctions.preDeployTask": "publish (functions)"
|
||||
>>>>>>> elsa3new
|
||||
}
|
||||
81
.vscode/tasks.json
vendored
Normal file
81
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "clean (functions)",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"clean",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"type": "process",
|
||||
"problemMatcher": "$msCompile",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/sk-azfunc-server"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "build (functions)",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"build",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"type": "process",
|
||||
"dependsOn": "clean (functions)",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": "$msCompile",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/sk-azfunc-server"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "clean release (functions)",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"clean",
|
||||
"--configuration",
|
||||
"Release",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"type": "process",
|
||||
"problemMatcher": "$msCompile",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/sk-azfunc-server"
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "publish (functions)",
|
||||
"command": "dotnet",
|
||||
"args": [
|
||||
"publish",
|
||||
"--configuration",
|
||||
"Release",
|
||||
"/property:GenerateFullPaths=true",
|
||||
"/consoleloggerparameters:NoSummary"
|
||||
],
|
||||
"type": "process",
|
||||
"dependsOn": "clean release (functions)",
|
||||
"problemMatcher": "$msCompile",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/sk-azfunc-server"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "func",
|
||||
"dependsOn": "build (functions)",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/sk-azfunc-server/bin/Debug/net7.0"
|
||||
},
|
||||
"command": "host start",
|
||||
"isBackground": true,
|
||||
"problemMatcher": "$func-dotnet-watch"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,240 @@
|
||||
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.SemanticKernel.SkillDefinition;
|
||||
using Microsoft.SKDevTeam;
|
||||
|
||||
namespace Elsa.SemanticKernel;
|
||||
|
||||
//<summary>
|
||||
// Loads the Semantic Kernel skills and then generates activites for each skill
|
||||
//</summary>
|
||||
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<IEnumerable<ActivityDescriptor>> GetDescriptorsAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
// get the kernel
|
||||
var kernel = KernelBuilder();
|
||||
|
||||
// get a list of skills in the assembly
|
||||
var skills = LoadSkillsFromAssemblyAsync("skills", kernel);
|
||||
SKContext context = kernel.CreateNewContext();
|
||||
var functionsAvailable = context.Skills.GetFunctionsView();
|
||||
|
||||
// create activity descriptors for each skilland function
|
||||
var activities = new List<ActivityDescriptor>();
|
||||
foreach (KeyValuePair<string, List<FunctionView>> skill in functionsAvailable.SemanticFunctions)
|
||||
{
|
||||
Console.WriteLine($"Creating Activities for Skill: {skill.Key}");
|
||||
foreach (FunctionView func in skill.Value)
|
||||
{
|
||||
activities.Add(CreateActivityDescriptorFromSkillAndFunction(func, cancellationToken));
|
||||
}
|
||||
}
|
||||
|
||||
return activities;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an activity descriptor from a skill and function.
|
||||
/// </summary>
|
||||
/// <param name="function">The semantic kernel function</param>
|
||||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
/// <returns>An activity descriptor.</returns>
|
||||
private ActivityDescriptor CreateActivityDescriptorFromSkillAndFunction(FunctionView function, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Create a fully qualified type name for the activity
|
||||
var thisNamespace = GetType().Namespace;
|
||||
var fullTypeName = $"{thisNamespace}.{function.SkillName}.{function.Name}";
|
||||
Console.WriteLine($"Creating Activity: {fullTypeName}");
|
||||
|
||||
// create inputs from the function parameters - the SemanticKernelSkill activity will be the base for each activity
|
||||
var inputs = new List<InputDescriptor>();
|
||||
foreach (var p in function.Parameters) { inputs.Add(CreateInputDescriptorFromSKParameter(p)); }
|
||||
inputs.Add(CreateInputDescriptor(typeof(string), "SkillName", function.SkillName, "The name of the skill to use (generated, do not change)"));
|
||||
inputs.Add(CreateInputDescriptor(typeof(string), "FunctionName", function.Name, "The name of the function to use (generated, do not change)"));
|
||||
inputs.Add(CreateInputDescriptor(typeof(int), "MaxRetries", KernelSettings.DefaultMaxRetries, "Max Retries to contact AI Service"));
|
||||
|
||||
return new ActivityDescriptor
|
||||
{
|
||||
Kind = ActivityKind.Task,
|
||||
Category = "Semantic Kernel",
|
||||
Description = function.Description,
|
||||
Name = function.Name,
|
||||
TypeName = fullTypeName,
|
||||
Namespace = $"{thisNamespace}.{function.SkillName}",
|
||||
DisplayName = $"{function.SkillName}.{function.Name}",
|
||||
Inputs = inputs,
|
||||
Outputs = new[] {new OutputDescriptor()},
|
||||
Constructor = context =>
|
||||
{
|
||||
// The constructor is called when an activity instance of this type is requested.
|
||||
|
||||
// Create the activity instance.
|
||||
var activityInstance = _activityFactory.Create<SemanticKernelSkill>(context);
|
||||
|
||||
// Customize the activity type name.
|
||||
activityInstance.Type = fullTypeName;
|
||||
|
||||
// Configure the activity's URL and method properties.
|
||||
activityInstance.SkillName = new Input<string?>(function.SkillName);
|
||||
activityInstance.FunctionName = new Input<string?>(function.Name);
|
||||
|
||||
return activityInstance;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates an input descriptor for a single line string
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the input field</param>
|
||||
/// <param name="description">The description of the input field</param>
|
||||
private InputDescriptor CreateInputDescriptor(Type inputType, string name, Object defaultValue, string description)
|
||||
{
|
||||
var inputDescriptor = new InputDescriptor
|
||||
{
|
||||
Description = description,
|
||||
DefaultValue = defaultValue,
|
||||
Type = inputType,
|
||||
Name = name,
|
||||
DisplayName = name,
|
||||
IsSynthetic = true, // This is a synthetic property, i.e. it is not part of the activity's .NET type.
|
||||
IsWrapped = true, // This property is wrapped within an Input<T> object.
|
||||
UIHint = InputUIHints.SingleLine,
|
||||
ValueGetter = activity => activity.SyntheticProperties.GetValueOrDefault(name),
|
||||
ValueSetter = (activity, value) => activity.SyntheticProperties[name] = value!,
|
||||
};
|
||||
return inputDescriptor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an input descriptor from an sk funciton parameter definition.
|
||||
/// </summary>
|
||||
/// <param name="parameter">The function parameter.</param>
|
||||
/// <returns>An input descriptor.</returns>
|
||||
private InputDescriptor CreateInputDescriptorFromSKParameter(ParameterView parameter)
|
||||
{
|
||||
var inputDescriptor = new InputDescriptor
|
||||
{
|
||||
Description = string.IsNullOrEmpty(parameter.Description) ? parameter.Name : parameter.Description,
|
||||
DefaultValue = string.IsNullOrEmpty(parameter.DefaultValue) ? string.Empty : parameter.DefaultValue,
|
||||
Type = typeof(string),
|
||||
Name = parameter.Name,
|
||||
DisplayName = parameter.Name,
|
||||
IsSynthetic = true, // This is a synthetic property, i.e. it is not part of the activity's .NET type.
|
||||
IsWrapped = true, // This property is wrapped within an Input<T> object.
|
||||
UIHint = InputUIHints.MultiLine,
|
||||
ValueGetter = activity => activity.SyntheticProperties.GetValueOrDefault(parameter.Name),
|
||||
ValueSetter = (activity, value) => activity.SyntheticProperties[parameter.Name] = value!,
|
||||
|
||||
};
|
||||
return inputDescriptor;
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// Gets a list of the skills in the assembly
|
||||
///</summary>
|
||||
private IEnumerable<string> LoadSkillsFromAssemblyAsync(string assemblyName, IKernel kernel)
|
||||
{
|
||||
var skills = new List<string>();
|
||||
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($"SKActivityProvider Added SK function: {skfunc.SkillName}.{skfunc.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return skills;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a semantic kernel instance
|
||||
/// </summary>
|
||||
/// <returns>Microsoft.SemanticKernel.IKernel</returns>
|
||||
private IKernel KernelBuilder()
|
||||
{
|
||||
var kernelSettings = KernelSettings.LoadSettings();
|
||||
var kernelConfig = new KernelConfig();
|
||||
|
||||
using ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
|
||||
{
|
||||
builder.SetMinimumLevel(kernelSettings.LogLevel ?? LogLevel.Warning);
|
||||
});
|
||||
|
||||
var kernel = new KernelBuilder()
|
||||
.WithLogger(loggerFactory.CreateLogger<IKernel>())
|
||||
.WithAzureChatCompletionService(kernelSettings.DeploymentOrModelId, kernelSettings.Endpoint, kernelSettings.ApiKey, true, kernelSettings.ServiceId, true)
|
||||
.WithConfiguration(kernelConfig)
|
||||
.Configure(c => c.SetDefaultHttpRetryConfig(new HttpRetryConfig
|
||||
{
|
||||
MaxRetryCount = KernelSettings.DefaultMaxRetries,
|
||||
UseExponentialBackoff = true,
|
||||
// MinRetryDelay = TimeSpan.FromSeconds(2),
|
||||
// MaxRetryDelay = TimeSpan.FromSeconds(8),
|
||||
MaxTotalRetryTime = TimeSpan.FromSeconds(300),
|
||||
// RetryableStatusCodes = new[] { HttpStatusCode.TooManyRequests, HttpStatusCode.RequestTimeout },
|
||||
// RetryableExceptions = new[] { typeof(HttpRequestException) }
|
||||
}))
|
||||
.Build();
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
245
Elsa.SemanticKernel/Activities/SemanticKernel.cs
Normal file
245
Elsa.SemanticKernel/Activities/SemanticKernel.cs
Normal file
@ -0,0 +1,245 @@
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Core;
|
||||
using Elsa.Workflows.Core.Attributes;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using JetBrains.Annotations;
|
||||
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.SemanticKernel.SkillDefinition;
|
||||
using Microsoft.SKDevTeam;
|
||||
|
||||
using System;
|
||||
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;
|
||||
|
||||
|
||||
namespace Elsa.SemanticKernel;
|
||||
|
||||
/// <summary>
|
||||
/// Invoke a Semantic Kernel skill.
|
||||
/// </summary>
|
||||
[Activity("Elsa", "Semantic Kernel", "Invoke a Semantic Kernel skill. ", DisplayName = "Generic Semantic Kernel Skill", Kind = ActivityKind.Task)]
|
||||
[PublicAPI]
|
||||
public class SemanticKernelSkill : CodeActivity<string>
|
||||
{
|
||||
[Input(
|
||||
Description = "System Prompt",
|
||||
UIHint = InputUIHints.MultiLine,
|
||||
DefaultValue = PromptDefaults.SystemPrompt)]
|
||||
public Input<string> SysPrompt { get; set; } = default!;
|
||||
|
||||
[Input(
|
||||
Description = "User Input Prompt",
|
||||
UIHint = InputUIHints.MultiLine,
|
||||
DefaultValue = PromptDefaults.UserPrompt)]
|
||||
public Input<string> Prompt { get; set; }
|
||||
|
||||
[Input(
|
||||
Description = "Max retries",
|
||||
UIHint = InputUIHints.SingleLine,
|
||||
DefaultValue = KernelSettings.DefaultMaxRetries)]
|
||||
public Input<int> MaxRetries { get; set; }
|
||||
|
||||
[Input(
|
||||
Description = "The skill to invoke from the semantic kernel",
|
||||
UIHint = InputUIHints.SingleLine,
|
||||
DefaultValue = "Chat")]
|
||||
public Input<string> SkillName { get; set; }
|
||||
|
||||
[Input(
|
||||
Description = "The function to invoke from the skill",
|
||||
UIHint = InputUIHints.SingleLine,
|
||||
DefaultValue = "ChatCompletion")]
|
||||
public Input<string> FunctionName { get; set; }
|
||||
|
||||
/* [Input(
|
||||
Description = "Mockup - don't actually call the AI, just output the prompts",
|
||||
UIHint = InputUIHints.Checkbox,
|
||||
DefaultValue = false)]
|
||||
public Input<bool> Mockup { get; set; } */
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async ValueTask ExecuteAsync(ActivityExecutionContext workflowContext)
|
||||
{
|
||||
var test = SkillName.Get(workflowContext);
|
||||
var skillName = SkillName.Get(workflowContext);
|
||||
var functionName = FunctionName.Get(workflowContext);
|
||||
var systemPrompt = SysPrompt.Get(workflowContext);
|
||||
var maxRetries = MaxRetries.Get(workflowContext);
|
||||
var prompt = Prompt.Get(workflowContext);
|
||||
//var mockup = Mockup.Get(workflowContext);
|
||||
var mockup = false;
|
||||
|
||||
string info = ($"#################\nSkill: {skillName}\nFunction: {functionName}\nPrompt: {prompt}\n#################\n\n");
|
||||
|
||||
if (mockup)
|
||||
{
|
||||
workflowContext.SetResult(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
// get the kernel
|
||||
var kernel = KernelBuilder();
|
||||
|
||||
// load the skill
|
||||
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);
|
||||
|
||||
// set the context (our prompt)
|
||||
var contextVars = new ContextVariables();
|
||||
contextVars.Set("input", prompt);
|
||||
|
||||
/* var interestingMemories = kernel.Memory.SearchAsync("ImportedMemories", prompt, 2);
|
||||
var wafContext = "Consider the following contextual snippets:";
|
||||
await foreach (var memory in interestingMemories)
|
||||
{
|
||||
wafContext += $"\n {memory.Metadata.Text}";
|
||||
} */
|
||||
|
||||
|
||||
//context.Set("wafContext", wafContext);
|
||||
|
||||
SKContext answer = await kernel.RunAsync(contextVars, function).ConfigureAwait(false);
|
||||
string result = answer.Result;
|
||||
|
||||
workflowContext.SetResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the skills into the kernel
|
||||
/// </summary>
|
||||
private string ListSkillsInKernel(IKernel kernel)
|
||||
{
|
||||
|
||||
var theSkills = LoadSkillsFromAssemblyAsync("skills", kernel);
|
||||
SKContext context = kernel.CreateNewContext();
|
||||
var functionsAvailable = context.Skills.GetFunctionsView();
|
||||
|
||||
var list = new StringBuilder();
|
||||
foreach (KeyValuePair<string, List<FunctionView>> 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()}");
|
||||
return list.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a semantic kernel instance
|
||||
/// </summary>
|
||||
/// <returns>Microsoft.SemanticKernel.IKernel</returns>
|
||||
private IKernel KernelBuilder()
|
||||
{
|
||||
var kernelSettings = KernelSettings.LoadSettings();
|
||||
var kernelConfig = new KernelConfig();
|
||||
|
||||
using ILoggerFactory loggerFactory = LoggerFactory.Create(builder =>
|
||||
{
|
||||
builder.SetMinimumLevel(kernelSettings.LogLevel ?? LogLevel.Warning);
|
||||
});
|
||||
|
||||
/*
|
||||
var memoryStore = new QdrantMemoryStore(new QdrantVectorDbClient("http://qdrant", 1536, port: 6333));
|
||||
var embedingGeneration = new AzureTextEmbeddingGeneration(kernelSettings.EmbeddingDeploymentOrModelId, kernelSettings.Endpoint, kernelSettings.ApiKey);
|
||||
var semanticTextMemory = new SemanticTextMemory(memoryStore, embedingGeneration);
|
||||
*/
|
||||
|
||||
var kernel = new KernelBuilder()
|
||||
.WithLogger(loggerFactory.CreateLogger<IKernel>())
|
||||
.WithAzureChatCompletionService(kernelSettings.DeploymentOrModelId, kernelSettings.Endpoint, kernelSettings.ApiKey, true, kernelSettings.ServiceId, true)
|
||||
//.WithMemory(semanticTextMemory)
|
||||
.WithConfiguration(kernelConfig)
|
||||
.Configure(c => c.SetDefaultHttpRetryConfig(new HttpRetryConfig
|
||||
{
|
||||
MaxRetryCount = KernelSettings.DefaultMaxRetries,
|
||||
UseExponentialBackoff = true,
|
||||
// MinRetryDelay = TimeSpan.FromSeconds(2),
|
||||
// MaxRetryDelay = TimeSpan.FromSeconds(8),
|
||||
MaxTotalRetryTime = TimeSpan.FromSeconds(300),
|
||||
// RetryableStatusCodes = new[] { HttpStatusCode.TooManyRequests, HttpStatusCode.RequestTimeout },
|
||||
// RetryableExceptions = new[] { typeof(HttpRequestException) }
|
||||
}))
|
||||
.Build();
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// Gets a list of the skills in the assembly
|
||||
///</summary>
|
||||
private IEnumerable<string> LoadSkillsFromAssemblyAsync(string assemblyName, IKernel kernel)
|
||||
{
|
||||
var skills = new List<string>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -4,12 +4,19 @@ using Microsoft.Extensions.Logging;
|
||||
using System.IO;
|
||||
using System;
|
||||
|
||||
<<<<<<< HEAD
|
||||
|
||||
=======
|
||||
>>>>>>> elsa3new
|
||||
internal class KernelSettings
|
||||
{
|
||||
public const string DefaultConfigFile = "config/appsettings.json";
|
||||
public const string OpenAI = "OPENAI";
|
||||
public const string AzureOpenAI = "AZUREOPENAI";
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
public const int DefaultMaxRetries = 9;
|
||||
>>>>>>> elsa3new
|
||||
|
||||
[JsonPropertyName("serviceType")]
|
||||
public string ServiceType { get; set; } = string.Empty;
|
||||
|
||||
7
Elsa.SemanticKernel/Config/PromptDefaults.cs
Normal file
7
Elsa.SemanticKernel/Config/PromptDefaults.cs
Normal file
@ -0,0 +1,7 @@
|
||||
internal static class PromptDefaults {
|
||||
public const string SystemPrompt = @"You are fulfilling roles on a software development team.
|
||||
Provide a response to the following prompt, do not provide any additional output.";
|
||||
|
||||
public const string UserPrompt = @"Let's build a ToDoList Application!";
|
||||
|
||||
}
|
||||
@ -5,11 +5,23 @@
|
||||
<Description>
|
||||
Activities for calling Semantic Kernel SDK
|
||||
</Description>
|
||||
<<<<<<< HEAD
|
||||
<PackageTags>elsa module semantic kerne activities</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Elsa" Version="3.0.0-rc1" />
|
||||
=======
|
||||
<PackageTags>elsa module semantic kernel activities</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Elsa" Version="3.0.0-preview.552" />
|
||||
<PackageReference Include="Elsa.Http" Version="3.0.0-preview.552" />
|
||||
<PackageReference Include="Elsa.Workflows.Api" Version="3.0.0-preview.552" />
|
||||
<PackageReference Include="Elsa.Workflows.Core" Version="3.0.0-preview.552" />
|
||||
<PackageReference Include="Elsa.Workflows.Management" Version="3.0.0-preview.552" />
|
||||
>>>>>>> elsa3new
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
|
||||
|
||||
@ -3,7 +3,11 @@
|
||||
<packageSources>
|
||||
<clear/>
|
||||
|
||||
<<<<<<< HEAD
|
||||
<add key="NuGet official package source" value="https://api.nuget.org/v3/index.json" />
|
||||
=======
|
||||
<!--add key="NuGet official package source" value="https://api.nuget.org/v3/index.json" /-->
|
||||
>>>>>>> elsa3new
|
||||
<add key="Jint prereleases" value="https://www.myget.org/F/jint/api/v3/index.json" />
|
||||
<add key="Elsa prereleases" value="https://f.feedz.io/elsa-workflows/elsa-3/nuget/index.json" />
|
||||
</packageSources>
|
||||
|
||||
136
README.md
136
README.md
@ -1,3 +1,4 @@
|
||||
<<<<<<< HEAD
|
||||
# sk-dev-team
|
||||
# Build a Virtual AI Dev Team using Semantic Kernel Skills
|
||||
## Status
|
||||
@ -56,12 +57,141 @@ The system will present a view that facilitates chain-of-thought coordination ac
|
||||
* Logging service streaming back to azure logs analytics, app insights, and teams channel
|
||||
* Deployment service – actions/pipelines driven
|
||||
* Azure Dev Skill – lean into azure integrations – crawl the azure estate to inventory a tenant’s existing resources to memory and help inform new code. Eg: you have a large azure sql estate? Ok, most likely you want to wire your new app to one of those dbs, etc….
|
||||
=======
|
||||
|
||||
# sk-dev-team
|
||||
|
||||
# Build a Virtual AI Dev Team using Semantic Kernel Skills
|
||||
|
||||
## Status
|
||||
|
||||
This is a nascent project - we will use the README to describe the project's intent - as we build it out we will document what exists and eventually move roadmap/intent to the discussion.
|
||||
|
||||
## Trying it out
|
||||
|
||||
### Elsa.SemanticKernel
|
||||
|
||||
SemanticKernel Activity Provider for Elsa Workflows 3.x
|
||||
|
||||
The project supports running [Microsoft Semantic Kernel](https://github.com/microsoft/semantic-kernel) Skills as workflows using [Elsa Workflows](https://v3.elsaworkflows.io). You can build the workflows as .NET code or in the visual designer.
|
||||
To run the designer:
|
||||
|
||||
```bash
|
||||
> cd WorkflowsApp
|
||||
> cp .env_example .env
|
||||
# Edit the .env file to choose your AI model, add your API Endpoint, and secrets.
|
||||
> bash .env
|
||||
> dotnet build
|
||||
> dotnet run
|
||||
# Open browser to the URI in the console output
|
||||
```
|
||||
|
||||
By Default you can use "admin" and "password" to login. Please review [Workflow Security](https://v3.elsaworkflows.io/docs/installation/aspnet-apps-workflow-server) for into on securing the app, using API tokens, and more.
|
||||
|
||||
To [invoke](https://v3.elsaworkflows.io/docs/guides/invoking-workflows) a workflow, first it must be "Published". If your workflow has a trigger activity, you can use that. When your workflow is ready, click the "Publish" button. You can also execute the workflow using the API. Then, find the Workflow Definition ID. From a command line, you can use "curl":
|
||||
|
||||
```bash
|
||||
> curl --location 'https://localhost:5001/elsa/api/workflow-definitions/{workflow_definition_id}/execute' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--header 'Authorization: ApiKey {api_key}' \
|
||||
--data '{
|
||||
}'
|
||||
```
|
||||
|
||||
Once you have the app runing locally, you can login (admin/password - see the [Elsa Workflows](https://v3.elsaworkflows.io) for info about securing). Then you can click "new workflow" to begin building your workflow with semantic kernel skills.
|
||||
|
||||
1. Drag workflow Activity blocks into the designer, and examine the settings.
|
||||
2. Connect the Activities to specify an order of operations.
|
||||
3. You can use Workfflow Variables to pass state between activities.
|
||||
1. Create a Workflow Variable, "MyVariable"
|
||||
2. Click on the Activity that you want to use to populate the variable.
|
||||
3. In the Settings box for the Activity, Click "Output"
|
||||
4. Set the "Output" to the variable chosen.
|
||||
5. Click the Activity that will use the variable. Click on "Settings".
|
||||
6. Find the text box representing the variable that you want to populate, in this case usually "input".
|
||||
7. Click the "..." widget above the text box, and select "javascript"
|
||||
8. Set the value of the text box to
|
||||
|
||||
```javascript
|
||||
`${getMyVariable()}`
|
||||
```
|
||||
|
||||
9. Run the workflow.
|
||||
|
||||
## Via CLI
|
||||
|
||||
The easiest way to run the project is in Codespaces. Codespaces will start a qdrant instance for you.
|
||||
|
||||
1. Create a new codespace from the *code* button on the main branch.
|
||||
2. Once the code space setup is finished, from the terminal:
|
||||
|
||||
```bash
|
||||
> cd cli
|
||||
cli> cp ../WorkflowsApp/.env_example .
|
||||
# Edit the .env file to choose your AI model, add your API Endpoint, and secrets.
|
||||
cli> bash .env
|
||||
cli> dotnet build
|
||||
cli> dotnet run --file util/ToDoListSamplePrompt.txt do it
|
||||
```
|
||||
|
||||
You will find the output in the *output/* directory.
|
||||
|
||||
# Goal
|
||||
|
||||
From a natural language specification, set out to integrate a team of AI copilot skills into your team’s dev process, either for discrete tasks on an existing repo (unit tests, pipeline expansions, PRs for specific intents), developing a new feature, or even building an application from scratch. Starting from an existing repo and a broad statement of intent, work with multiple AI copilot dev skills, each of which has a different emphasis - from architecture, to task breakdown, to plans for individual tasks, to code output, code review, efficiency, documentation, build, writing tests, setting up pipelines, deployment, integration tests, and then validation.
|
||||
The system will present a view that facilitates chain-of-thought coordination across multiple trees of reasoning with the dev team skills.
|
||||
|
||||
## Proposed UX
|
||||
|
||||
* Possible UI: Start with an existing repo (GH or ADO), either populated or empty, and API Keys / config for access – once configured / loaded split view between three columns:
|
||||
* Settings/History/Tasks (allows browsing into each of the chats with a copilot dev team role) | [Central Window Chat interface with Copilot DevTeam] | Repo browsing/editing
|
||||
* Alternate interface will be via VS Code plugin/other IDE plugins, following the plugin idiom for each IDE
|
||||
* Settings include teams channel for conversations, repo config and api keys, model config and api keys, and any desired prompt template additions
|
||||
* CLI: start simple with a CLI that can be passed a file as prompt input and takes optional arguments as to which skills to invoke
|
||||
* User begins with specifying a repository and then statement of what they want to accomplish, natural language, as simple or as detailed as needed.
|
||||
* SK DevTeam skill will use dialog to refine the intent as needed, returns a plan, proposes necessary steps
|
||||
* User approves the plan or gives feedback, requests iteration
|
||||
* Plan is parceled out to the appropriate further skills
|
||||
* Eg, for a new app:
|
||||
* Architecture is passed to DevLead skill gives plan/task breakdown.
|
||||
* DevLead breaks down tasks into smaller tasks, each of these is fed to a skill to decide if it is a single code module or multiple
|
||||
* Each module is further fed to a dev lead to break down again or specify a prompt for a coder
|
||||
* Each code module prompt is fed to a coder
|
||||
* Each module output from a coder is fed to a code reviewer (with context, specific goals)
|
||||
* Each reviewer proposes changes, which result in a new prompt for the original coder
|
||||
* Changes are accepted by the coder
|
||||
* Each module fed to a builder
|
||||
* If it doesn’t build sent back to review
|
||||
* (etc)
|
||||
|
||||
## Proposed Architecture
|
||||
|
||||
* SK Kernel Service – ASP.NET Core Service with REST API
|
||||
* SK Skills:
|
||||
* PM Skill – generates pot, word docs, describing app,
|
||||
* Designer Skill – mockups?
|
||||
* Architect Skill – proposes overall arch
|
||||
* DevLead Skill – proposes task breakdown
|
||||
* CoderSkill – builds code modules for each task
|
||||
* ReviewerSkill – improves code modules
|
||||
* TestSkill – writes tests
|
||||
* Etc
|
||||
* Web app: prompt front end and wizard style editor of app
|
||||
* Build service sandboxes – using branches and actions/pipelines 1st draft; Alternate – ephemeral build containers
|
||||
* Logging service streaming back to azure logs analytics, app insights, and teams channel
|
||||
* Deployment service – actions/pipelines driven
|
||||
* Azure Dev Skill – lean into azure integrations – crawl the azure estate to inventory a tenant’s existing resources to memory and help inform new code. Eg: you have a large azure sql estate? Ok, most likely you want to wire your new app to one of those dbs, etc….
|
||||
>>>>>>> elsa3new
|
||||
|
||||
# Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
<<<<<<< HEAD
|
||||
the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
|
||||
=======
|
||||
the rights to use your contribution. For details, visit <https://cla.opensource.microsoft.com>.
|
||||
>>>>>>> elsa3new
|
||||
|
||||
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
|
||||
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
|
||||
@ -81,9 +211,15 @@ see the [LICENSE](LICENSE) file, and grant you a license to any code in the repo
|
||||
Microsoft, Windows, Microsoft Azure and/or other Microsoft products and services referenced in the documentation
|
||||
may be either trademarks or registered trademarks of Microsoft in the United States and/or other countries.
|
||||
The licenses for this project do not grant you rights to use any Microsoft names, logos, or trademarks.
|
||||
<<<<<<< HEAD
|
||||
Microsoft's general trademark guidelines can be found at http://go.microsoft.com/fwlink/?LinkID=254653.
|
||||
|
||||
Privacy information can be found at https://privacy.microsoft.com/en-us/
|
||||
=======
|
||||
Microsoft's general trademark guidelines can be found at <http://go.microsoft.com/fwlink/?LinkID=254653>.
|
||||
|
||||
Privacy information can be found at <https://privacy.microsoft.com/en-us/>
|
||||
>>>>>>> elsa3new
|
||||
|
||||
Microsoft and any contributors reserve all other rights, whether under their respective copyrights, patents,
|
||||
or trademarks, whether by implication, estoppel or otherwise.
|
||||
|
||||
8
WorkflowsApp/.env_example
Normal file
8
WorkflowsApp/.env_example
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
# Replace with your own values
|
||||
export SERVICETYPE=AzureOpenAI
|
||||
export SERVICEID=gpt-4
|
||||
export DEPLOYMENTORMODELID=gpt-4
|
||||
export EMBEDDINGDEPLOYMENTORMODELID=text-embedding-ada-002
|
||||
export ENDPOINT="Error - you mus update your OpenAI Endpoint"
|
||||
export APIKEY="Error - you must update your OpenAPI or Azure API key"
|
||||
10
WorkflowsApp/NuGet.Config
Normal file
10
WorkflowsApp/NuGet.Config
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear/>
|
||||
|
||||
<!--add key="NuGet official package source" value="https://api.nuget.org/v3/index.json" /-->
|
||||
<add key="Jint prereleases" value="https://www.myget.org/F/jint/api/v3/index.json" />
|
||||
<add key="Elsa prereleases" value="https://f.feedz.io/elsa-workflows/elsa-3/nuget/index.json" />
|
||||
</packageSources>
|
||||
</configuration>
|
||||
22
WorkflowsApp/Pages/Index.cshtml
Normal file
22
WorkflowsApp/Pages/Index.cshtml
Normal file
@ -0,0 +1,22 @@
|
||||
@page "/"
|
||||
@{
|
||||
var serverUrl = $"{Request.Scheme}://{Request.Host}{Request.PathBase}{Request.Path}";
|
||||
var apiUrl = serverUrl + "elsa/api";
|
||||
}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>Elsa Workflows 3.0</title>
|
||||
<link rel="stylesheet" href="https://rsms.me/inter/inter.css">
|
||||
<link rel="stylesheet" href="_content/Elsa.Workflows.Designer/elsa-workflows-designer/elsa-workflows-designer.css">
|
||||
<script src="_content/Elsa.Workflows.Designer/monaco-editor/min/vs/loader.js"></script>
|
||||
<script type="module" src="_content/Elsa.Workflows.Designer/elsa-workflows-designer/elsa-workflows-designer.esm.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<elsa-studio server="@apiUrl" monaco-lib-path="/_content/Elsa.Workflows.Designer/monaco-editor/min"></elsa-studio>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
2
WorkflowsApp/Pages/_ViewImports.cshtml
Normal file
2
WorkflowsApp/Pages/_ViewImports.cshtml
Normal file
@ -0,0 +1,2 @@
|
||||
@namespace WorkflowsApp.Pages
|
||||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
|
||||
56
WorkflowsApp/Program.cs
Normal file
56
WorkflowsApp/Program.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using Elsa.EntityFrameworkCore.Extensions;
|
||||
using Elsa.EntityFrameworkCore.Modules.Management;
|
||||
using Elsa.EntityFrameworkCore.Modules.Runtime;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Core.Models;
|
||||
using Elsa.Identity.Features;
|
||||
using Elsa.SemanticKernel;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddElsa(elsa =>
|
||||
{
|
||||
// Configure management feature to use EF Core.
|
||||
elsa.UseWorkflowManagement(management => management.UseEntityFrameworkCore(ef => ef.UseSqlite()));
|
||||
|
||||
elsa.UseWorkflowRuntime(runtime =>runtime.UseEntityFrameworkCore());
|
||||
|
||||
// Expose API endpoints.
|
||||
elsa.UseWorkflowsApi();
|
||||
|
||||
// Add services for HTTP activities and workflow middleware.
|
||||
elsa.UseHttp();
|
||||
|
||||
// Configure identity so that we can create a default admin user.
|
||||
elsa.UseIdentity(identity =>
|
||||
{
|
||||
identity.UseAdminUserProvider();
|
||||
identity.TokenOptions = options => options.SigningKey = "secret-token-signing-key";
|
||||
});
|
||||
|
||||
// Use default authentication (JWT + API Key).
|
||||
elsa.UseDefaultAuthentication(auth => auth.UseAdminApiKey());
|
||||
|
||||
// Add Semantic Kernel skill.
|
||||
elsa.AddActivity<SemanticKernelSkill>();
|
||||
|
||||
});
|
||||
|
||||
// Add dynamic Activity Provider for SK skills.
|
||||
builder.Services.AddActivityProvider<SemanticKernelActivityProvider>();
|
||||
|
||||
// Add Razor pages.
|
||||
builder.Services.AddRazorPages();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseWorkflowsApi();
|
||||
app.UseWorkflows();
|
||||
app.MapRazorPages();
|
||||
app.Run();
|
||||
37
WorkflowsApp/Properties/launchSettings.json
Normal file
37
WorkflowsApp/Properties/launchSettings.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:10492",
|
||||
"sslPort": 44312
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:5181",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:7077;http://localhost:5181",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
WorkflowsApp/WorkflowsApp.csproj
Normal file
29
WorkflowsApp/WorkflowsApp.csproj
Normal file
@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Elsa" Version="3.0.0-preview.552" />
|
||||
<PackageReference Include="Elsa.EntityFrameworkCore" Version="3.0.0-preview.552" />
|
||||
<PackageReference Include="Elsa.EntityFrameworkCore.Sqlite" Version="3.0.0-preview.552" />
|
||||
<PackageReference Include="Elsa.Http" Version="3.0.0-preview.552" />
|
||||
<PackageReference Include="Elsa.Identity" Version="3.0.0-preview.552" />
|
||||
<PackageReference Include="Elsa.Workflows.Api" Version="3.0.0-preview.552" />
|
||||
<PackageReference Include="Elsa.Workflows.Designer" Version="3.0.0-preview.552" /><!--
|
||||
<PackageReference Include="Elsa.EntityFrameworkCore" Version="3.0.0-rc1" />
|
||||
<PackageReference Include="Elsa.EntityFrameworkCore.Sqlite" Version="3.0.0-rc1" />
|
||||
<PackageReference Include="Elsa.Http" Version="3.0.0-rc1" />
|
||||
<PackageReference Include="Elsa.Identity" Version="3.0.0-rc1" />
|
||||
<PackageReference Include="Elsa.Workflows.Api" Version="3.0.0-rc1" />
|
||||
<PackageReference Include="Elsa.Workflows.Designer" Version="3.0.0-rc1" /> -->
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Elsa.SemanticKernel\Elsa.SemanticKernel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
8
WorkflowsApp/appsettings.Development.json
Normal file
8
WorkflowsApp/appsettings.Development.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,12 @@ using Microsoft.SemanticKernel.Connectors.Memory.Qdrant;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
using Microsoft.SemanticKernel.Orchestration;
|
||||
using Microsoft.SemanticKernel.Reliability;
|
||||
<<<<<<< HEAD
|
||||
using skills;
|
||||
=======
|
||||
using Microsoft.SKDevTeam;
|
||||
|
||||
>>>>>>> elsa3new
|
||||
|
||||
class Program
|
||||
{
|
||||
@ -34,7 +39,11 @@ class Program
|
||||
|
||||
var pmCommand = new Command("pm", "Commands for the PM team");
|
||||
var pmReadmeCommand = new Command("readme", "Produce a Readme for a given input");
|
||||
<<<<<<< HEAD
|
||||
pmReadmeCommand.SetHandler(async (file, maxRetry) => await CallWithFile<string>(nameof(PM), PM.Readme , file.FullName, maxRetry), fileOption, maxRetryOption);
|
||||
=======
|
||||
pmReadmeCommand.SetHandler(async (file, maxRetry) => await CallWithFile<string>(nameof(PM), PM.Readme, file.FullName, maxRetry), fileOption, maxRetryOption);
|
||||
>>>>>>> elsa3new
|
||||
|
||||
var pmBootstrapCommand = new Command("bootstrap", "Bootstrap a project for a given input");
|
||||
pmBootstrapCommand.SetHandler(async (file, maxRetry) => await CallWithFile<string>(nameof(PM), PM.BootstrapProject, file.FullName, maxRetry), fileOption, maxRetryOption);
|
||||
@ -51,7 +60,11 @@ class Program
|
||||
var devPlanCommand = new Command("plan", "Implement the module for a given input");
|
||||
devPlanCommand.SetHandler(async (file, maxRetry) => await CallWithFile<string>(nameof(Developer), Developer.Implement, file.FullName, maxRetry), fileOption, maxRetryOption);
|
||||
devCommand.AddCommand(devPlanCommand);
|
||||
<<<<<<< HEAD
|
||||
|
||||
=======
|
||||
|
||||
>>>>>>> elsa3new
|
||||
rootCommand.AddCommand(pmCommand);
|
||||
rootCommand.AddCommand(devleadCommand);
|
||||
rootCommand.AddCommand(devCommand);
|
||||
@ -67,7 +80,11 @@ class Program
|
||||
|
||||
Console.WriteLine($"Using output directory: {outputPath}");
|
||||
|
||||
<<<<<<< HEAD
|
||||
var readme = await CallWithFile<string>(nameof(PM), PM.Readme , file, maxRetry);
|
||||
=======
|
||||
var readme = await CallWithFile<string>(nameof(PM), PM.Readme, file, maxRetry);
|
||||
>>>>>>> elsa3new
|
||||
string readmeFile = Path.Combine(outputPath.FullName, "README.md");
|
||||
await SaveToFile(readmeFile, readme);
|
||||
Console.WriteLine($"Saved README to {readmeFile}");
|
||||
@ -83,12 +100,21 @@ class Program
|
||||
|
||||
var implementationTasks = plan.steps.SelectMany(
|
||||
(step) => step.subtasks.Select(
|
||||
<<<<<<< HEAD
|
||||
async (subtask) => {
|
||||
=======
|
||||
async (subtask) =>
|
||||
{
|
||||
>>>>>>> elsa3new
|
||||
Console.WriteLine($"Implementing {step.step}-{subtask.subtask}");
|
||||
var implementationResult = string.Empty;
|
||||
while (true)
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
try
|
||||
=======
|
||||
try
|
||||
>>>>>>> elsa3new
|
||||
{
|
||||
implementationResult = await CallFunction<string>(nameof(Developer), Developer.Implement, subtask.LLM_prompt, maxRetry);
|
||||
break;
|
||||
@ -105,7 +131,12 @@ class Program
|
||||
}
|
||||
await sandboxSkill.RunInDotnetAlpineAsync(implementationResult);
|
||||
await SaveToFile(Path.Combine(outputPath.FullName, $"{step.step}-{subtask.subtask}.sh"), implementationResult);
|
||||
<<<<<<< HEAD
|
||||
return implementationResult; }));
|
||||
=======
|
||||
return implementationResult;
|
||||
}));
|
||||
>>>>>>> elsa3new
|
||||
await Task.WhenAll(implementationTasks);
|
||||
}
|
||||
|
||||
@ -115,8 +146,13 @@ class Program
|
||||
}
|
||||
|
||||
public static async Task<T> CallWithFile<T>(string skillName, string functionName, string filePath, int maxRetry)
|
||||
<<<<<<< HEAD
|
||||
{
|
||||
if(!File.Exists(filePath))
|
||||
=======
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
>>>>>>> elsa3new
|
||||
throw new FileNotFoundException($"File not found: {filePath}", filePath);
|
||||
var input = File.ReadAllText(filePath);
|
||||
return await CallFunction<T>(skillName, functionName, input, maxRetry);
|
||||
@ -173,10 +209,19 @@ class Program
|
||||
var answer = await kernel.RunAsync(context, function).ConfigureAwait(false);
|
||||
var result = typeof(T) != typeof(string) ? JsonSerializer.Deserialize<T>(answer.ToString()) : (T)(object)answer.ToString();
|
||||
//Console.WriteLine(answer);
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
>>>>>>> elsa3new
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PM { public static string Readme = "Readme"; public static string BootstrapProject = "BootstrapProject"; }
|
||||
<<<<<<< HEAD
|
||||
public static class DevLead { public static string Plan="Plan"; }
|
||||
public static class Developer { public static string Implement="Implement"; public static string Improve="Improve";}
|
||||
=======
|
||||
public static class DevLead { public static string Plan = "Plan"; }
|
||||
public static class Developer { public static string Implement = "Implement"; public static string Improve = "Improve"; }
|
||||
>>>>>>> elsa3new
|
||||
|
||||
@ -6,7 +6,12 @@ using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Orchestration;
|
||||
using Models;
|
||||
<<<<<<< HEAD
|
||||
using skills;
|
||||
=======
|
||||
using Microsoft.SKDevTeam;
|
||||
|
||||
>>>>>>> elsa3new
|
||||
|
||||
public class ExecuteFunctionEndpoint
|
||||
{
|
||||
@ -35,6 +40,13 @@ public class ExecuteFunctionEndpoint
|
||||
try
|
||||
{
|
||||
var functionRequest = await JsonSerializer.DeserializeAsync<ExecuteFunctionRequest>(requestData.Body, s_jsonOptions).ConfigureAwait(false);
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
if (functionRequest == null)
|
||||
{
|
||||
return await CreateResponseAsync(requestData, HttpStatusCode.BadRequest, new ErrorResponse() { Message = $"Invalid request body." }).ConfigureAwait(false);
|
||||
}
|
||||
>>>>>>> elsa3new
|
||||
|
||||
var skillConfig = SemanticFunctionConfig.ForSkillAndFunction(skillName, functionName);
|
||||
var function = _kernel.CreateSemanticFunction(skillConfig.PromptTemplate, skillConfig.Name, skillConfig.SkillName,
|
||||
|
||||
21
skills/Chat.cs
Normal file
21
skills/Chat.cs
Normal file
@ -0,0 +1,21 @@
|
||||
namespace Microsoft.SKDevTeam;
|
||||
public static class Chat
|
||||
{
|
||||
public static SemanticFunctionConfig ChatCompletion = new SemanticFunctionConfig
|
||||
{
|
||||
PromptTemplate = """
|
||||
You are a helpful assistant. Please complete the prompt as instructed in the Input.
|
||||
Provide as many references and links as needed to support the accuracy of your answer.
|
||||
Input: {{$input}}
|
||||
""",
|
||||
Name = nameof(ChatCompletion),
|
||||
SkillName = nameof(Chat),
|
||||
Description = "Use the Model as a Chatbot.",
|
||||
MaxTokens = 6500,
|
||||
Temperature = 0.0,
|
||||
TopP = 0.0,
|
||||
PPenalty = 0.0,
|
||||
FPenalty = 0.0
|
||||
};
|
||||
|
||||
}
|
||||
29
skills/CodeExplainer.cs
Normal file
29
skills/CodeExplainer.cs
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
namespace Microsoft.SKDevTeam;
|
||||
public static class CodeExplainer {
|
||||
public static SemanticFunctionConfig Explain = new SemanticFunctionConfig
|
||||
{
|
||||
PromptTemplate = """
|
||||
You are a Software Developer.
|
||||
Please explain the code that is in the input below. You can include references or documentation links in your explanation.
|
||||
Also where appropriate please output a list of keywords to describe the code or its capabilities.
|
||||
example:
|
||||
Keywords: Azure, networking, security, authentication
|
||||
|
||||
If the code's purpose is not clear output an error:
|
||||
Error: The model could not determine the purpose of the code.
|
||||
|
||||
--
|
||||
Input: {{$input}}
|
||||
""",
|
||||
Name = nameof(Explain),
|
||||
SkillName = nameof(CodeExplainer),
|
||||
Description = "From a description of a coding task out put the code or scripts necessary to complete the task.",
|
||||
MaxTokens = 6500,
|
||||
Temperature = 0.0,
|
||||
TopP = 0.0,
|
||||
PPenalty = 0.0,
|
||||
FPenalty = 0.0
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,4 +1,8 @@
|
||||
<<<<<<< HEAD
|
||||
namespace skills;
|
||||
=======
|
||||
namespace Microsoft.SKDevTeam;
|
||||
>>>>>>> elsa3new
|
||||
public static class DevLead {
|
||||
public static SemanticFunctionConfig Plan = new SemanticFunctionConfig
|
||||
{
|
||||
@ -9,7 +13,46 @@ public static class DevLead {
|
||||
For each step or module then break down the steps or subtasks required to complete that step or module.
|
||||
For each subtask write an LLM prompt that would be used to tell a model to write the coee that will accomplish that subtask. If the subtask involves taking action/running commands tell the model to write the script that will run those commands.
|
||||
In each LLM prompt restrict the model from outputting other text that is not in the form of code or code comments.
|
||||
<<<<<<< HEAD
|
||||
Please output a JSON data structure with a list of steps and a description of each step, and the steps or subtasks that each requires, and the LLM prompts for each subtask.
|
||||
=======
|
||||
Please output a JSON array data structure with a list of steps and a description of each step, and the steps or subtasks that each requires, and the LLM prompts for each subtask.
|
||||
Example:
|
||||
[
|
||||
{
|
||||
"step": "Step 1",
|
||||
"description": "This is the first step",
|
||||
"subtasks": [
|
||||
{
|
||||
"subtask": "Subtask 1",
|
||||
"description": "This is the first subtask",
|
||||
"prompt": "Write the code to do the first subtask"
|
||||
},
|
||||
{
|
||||
"subtask": "Subtask 2",
|
||||
"description": "This is the second subtask",
|
||||
"prompt": "Write the code to do the second subtask"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"step": "Step 2",
|
||||
"description": "This is the second step",
|
||||
"subtasks": [
|
||||
{
|
||||
"subtask": "Subtask 1",
|
||||
"description": "This is the first subtask",
|
||||
"prompt": "Write the code to do the first subtask"
|
||||
},
|
||||
{
|
||||
"subtask": "Subtask 2",
|
||||
"description": "This is the second subtask",
|
||||
"prompt": "Write the code to do the second subtask"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
>>>>>>> elsa3new
|
||||
Do not output any other text.
|
||||
Input: {{$input}}
|
||||
{{$wafContext}}
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
|
||||
<<<<<<< HEAD
|
||||
namespace skills;
|
||||
=======
|
||||
namespace Microsoft.SKDevTeam;
|
||||
>>>>>>> elsa3new
|
||||
public static class Developer {
|
||||
public static SemanticFunctionConfig Implement = new SemanticFunctionConfig
|
||||
{
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
<<<<<<< HEAD
|
||||
namespace skills;
|
||||
=======
|
||||
namespace Microsoft.SKDevTeam;
|
||||
>>>>>>> elsa3new
|
||||
public static class PM
|
||||
{
|
||||
public static SemanticFunctionConfig BootstrapProject = new SemanticFunctionConfig
|
||||
|
||||
@ -1,4 +1,8 @@
|
||||
<<<<<<< HEAD
|
||||
namespace skills;
|
||||
=======
|
||||
namespace Microsoft.SKDevTeam;
|
||||
>>>>>>> elsa3new
|
||||
|
||||
public class SemanticFunctionConfig
|
||||
{
|
||||
@ -14,9 +18,17 @@ public class SemanticFunctionConfig
|
||||
public static SemanticFunctionConfig ForSkillAndFunction(string skillName, string functionName) =>
|
||||
(skillName, functionName) switch
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
(nameof(PM), nameof(PM.BootstrapProject)) => PM.BootstrapProject,
|
||||
(nameof(PM), nameof(PM.Readme)) => PM.Readme,
|
||||
(nameof(DevLead), nameof(DevLead.Plan)) => DevLead.Plan,
|
||||
=======
|
||||
(nameof(Chat), nameof(Chat.ChatCompletion)) => Chat.ChatCompletion,
|
||||
(nameof(PM), nameof(PM.BootstrapProject)) => PM.BootstrapProject,
|
||||
(nameof(PM), nameof(PM.Readme)) => PM.Readme,
|
||||
(nameof(DevLead), nameof(DevLead.Plan)) => DevLead.Plan,
|
||||
(nameof(CodeExplainer), nameof(CodeExplainer.Explain)) => CodeExplainer.Explain,
|
||||
>>>>>>> elsa3new
|
||||
(nameof(Developer), nameof(Developer.Implement)) => Developer.Implement,
|
||||
(nameof(Developer), nameof(Developer.Improve)) => Developer.Improve,
|
||||
_ => throw new ArgumentException($"Unable to find {skillName}.{functionName}")
|
||||
|
||||
@ -4,7 +4,10 @@
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<<<<<<< HEAD
|
||||
<RootNamespace>skills</RootNamespace>
|
||||
=======
|
||||
>>>>>>> elsa3new
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user