diff --git a/.vscode/launch.json b/.vscode/launch.json
index 4d302d2..dfd58b6 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -10,11 +10,9 @@
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/apps/SKonsole/bin/Debug/net7.0/SKonsole.dll",
- "args": [
- /*"commit"*/
- ],
+ "args": ["stepwise", "optionset", "bing++"],
"cwd": "${workspaceFolder}",
- "console": "internalConsole",
+ "console": "integratedTerminal",
"stopAtEntry": false
},
{
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 21b4385..d9853b3 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -1,41 +1,52 @@
{
- "version": "2.0.0",
- "tasks": [
- {
- "label": "build",
- "command": "dotnet",
- "type": "process",
- "args": [
- "build",
- "${workspaceFolder}/apps/SKonsole/SKonsole.csproj",
- "/property:GenerateFullPaths=true",
- "/consoleloggerparameters:NoSummary"
- ],
- "problemMatcher": "$msCompile"
- },
- {
- "label": "publish",
- "command": "dotnet",
- "type": "process",
- "args": [
- "publish",
- "${workspaceFolder}/apps/SKonsole/SKonsole.csproj",
- "/property:GenerateFullPaths=true",
- "/consoleloggerparameters:NoSummary"
- ],
- "problemMatcher": "$msCompile"
- },
- {
- "label": "watch",
- "command": "dotnet",
- "type": "process",
- "args": [
- "watch",
- "run",
- "--project",
- "${workspaceFolder}/apps/SKonsole/SKonsole.csproj"
- ],
- "problemMatcher": "$msCompile"
- }
- ]
-}
\ No newline at end of file
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}/apps/SKonsole/SKonsole.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "format",
+ "command": "dotnet",
+ "type": "process",
+ "args": ["format", "${workspaceFolder}/skonsole.sln"],
+ "problemMatcher": "$msCompile",
+ "group": {
+ "kind": "test",
+ "isDefault": true
+ }
+ },
+ {
+ "label": "publish",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "publish",
+ "${workspaceFolder}/apps/SKonsole/SKonsole.csproj",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ },
+ {
+ "label": "watch",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "watch",
+ "run",
+ "--project",
+ "${workspaceFolder}/apps/SKonsole/SKonsole.csproj"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 288cf5d..90e2215 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -8,10 +8,10 @@
-
-
-
-
+
+
+
+
diff --git a/apps/SKonsole/Commands/CommitCommand.cs b/apps/SKonsole/Commands/CommitCommand.cs
index 0e10576..deff8be 100644
--- a/apps/SKonsole/Commands/CommitCommand.cs
+++ b/apps/SKonsole/Commands/CommitCommand.cs
@@ -98,9 +98,9 @@ private static async Task RunCommitMessage(CancellationToken token, ILogger logg
}
}
- var pullRequestSkill = kernel.ImportSkill(new PRSkill.PullRequestSkill(kernel));
+ var pullRequestSkill = kernel.ImportFunctions(new PRSkill.PullRequestSkill(kernel));
- void HorizontalRule(string title, string style = "white bold")
+ static void HorizontalRule(string title, string style = "white bold")
{
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule($"[{style}]{title}[/]").RuleStyle("grey").LeftJustified());
@@ -121,7 +121,7 @@ void HorizontalRule(string title, string style = "white bold")
var kernelResponse = await kernel.RunAsync(output, token, pullRequestSkill["GenerateCommitMessage"]);
task.StopTask();
- var result = kernelResponse.Result;
+ var result = kernelResponse.GetValue() ?? string.Empty;
await ClipboardService.SetTextAsync(result);
return result;
});
diff --git a/apps/SKonsole/Commands/PRCommand.cs b/apps/SKonsole/Commands/PRCommand.cs
index 6cb0364..a1e5439 100644
--- a/apps/SKonsole/Commands/PRCommand.cs
+++ b/apps/SKonsole/Commands/PRCommand.cs
@@ -61,6 +61,7 @@ public PRCommand(ConfigurationProvider config, ILogger? logger = null) : base("p
{
return context.ParseResult.GetValueForOption(option);
}
+
private Command GeneratePRFeedbackCommand(Option targetBranchOption)
{
var prFeedbackCommand = new Command("feedback", "Pull Request feedback subcommand");
@@ -106,11 +107,11 @@ private static async Task RunPullRequestFeedback(CancellationToken token, ILogge
string output = await process.StandardOutput.ReadToEndAsync();
- var pullRequestSkill = kernel.ImportSkill(new PRSkill.PullRequestSkill(kernel));
+ var pullRequestSkill = kernel.ImportFunctions(new PRSkill.PullRequestSkill(kernel));
var kernelResponse = await kernel.RunAsync(output, token, pullRequestSkill["GeneratePullRequestFeedback"]);
- logger.LogInformation("Pull Request Feedback:\n{result}", kernelResponse.Result);
+ logger.LogInformation("Pull Request Feedback:\n{result}", kernelResponse.GetValue());
}
private static async Task RunPullRequestDescription(CancellationToken token, ILogger logger, string targetBranch = "origin/main", string outputFormat = "", string outputFile = "", string diffInputFile = "")
@@ -119,13 +120,13 @@ private static async Task RunPullRequestDescription(CancellationToken token, ILo
var output = await FetchDiff(targetBranch, diffInputFile);
- var pullRequestSkill = kernel.ImportSkill(new PRSkill.PullRequestSkill(kernel));
+ var pullRequestSkill = kernel.ImportFunctions(new PRSkill.PullRequestSkill(kernel));
var contextVariables = new ContextVariables(output);
contextVariables.Set("outputFormatInstructions", PRSkill.Utils.FormatInstructionsProvider.GetOutputFormatInstructions(outputFormat));
var kernelResponse = await kernel.RunAsync(contextVariables, token, pullRequestSkill["GeneratePR"]);
- logger.LogInformation("Pull Request Description:\n{result}", kernelResponse.Result);
+ logger.LogInformation("Pull Request Description:\n{result}", kernelResponse.GetValue());
if (!string.IsNullOrEmpty(outputFile))
{
@@ -134,7 +135,7 @@ private static async Task RunPullRequestDescription(CancellationToken token, ILo
{
Directory.CreateDirectory(directory);
}
- System.IO.File.WriteAllText(outputFile, kernelResponse.Result);
+ System.IO.File.WriteAllText(outputFile, kernelResponse.GetValue());
}
}
diff --git a/apps/SKonsole/Commands/PlannerCommand.cs b/apps/SKonsole/Commands/PlannerCommand.cs
index ffb2477..7191ade 100644
--- a/apps/SKonsole/Commands/PlannerCommand.cs
+++ b/apps/SKonsole/Commands/PlannerCommand.cs
@@ -1,9 +1,8 @@
using System.CommandLine;
using Microsoft.Extensions.Logging;
-using Microsoft.SemanticKernel;
-using Microsoft.SemanticKernel.Planning;
-using Microsoft.SemanticKernel.Skills.Web;
-using Microsoft.SemanticKernel.Skills.Web.Bing;
+using Microsoft.SemanticKernel.Planners;
+using Microsoft.SemanticKernel.Plugins.Web;
+using Microsoft.SemanticKernel.Plugins.Web.Bing;
using SKonsole.Skills;
using SKonsole.Utils;
@@ -31,8 +30,10 @@ private Command GenerateCreatePlanCommand()
{
var messageArgument = new Argument
("message", "An argument that is parsed as a string.");
- var createPlanCommand = new Command("create", "Create Plan subcommand");
- createPlanCommand.Add(messageArgument);
+ var createPlanCommand = new Command("create", "Create Plan subcommand")
+ {
+ messageArgument
+ };
createPlanCommand.SetHandler(async (messageArgumentValue) => await RunCreatePlan(CancellationToken.None, this._logger, messageArgumentValue), messageArgument);
return createPlanCommand;
}
@@ -42,22 +43,22 @@ private static async Task RunCreatePlan(CancellationToken token, ILogger logger,
var kernel = KernelProvider.Instance.Get();
// Eventually, Kernel will be smarter about what skills it uses for an ask.
- // kernel.ImportSkill(new EmailSkill(), "email");
- // kernel.ImportSkill(new GitSkill(), "git");
- // kernel.ImportSkill(new SearchUrlSkill(), "url");
- // kernel.ImportSkill(new HttpSkill(), "http");
- // kernel.ImportSkill(new PRSkill.PullRequestSkill(kernel), "PullRequest");
+ // kernel.ImportFunctions(new EmailSkill(), "email");
+ // kernel.ImportFunctions(new GitSkill(), "git");
+ // kernel.ImportFunctions(new SearchUrlSkill(), "url");
+ // kernel.ImportFunctions(new HttpSkill(), "http");
+ // kernel.ImportFunctions(new PRSkill.PullRequestSkill(kernel), "PullRequest");
- kernel.ImportSkill(new WriterSkill(kernel), "writer");
+ kernel.ImportFunctions(new WriterSkill(kernel), "writer");
var bingConnector = new BingConnector(Configuration.ConfigVar("BING_API_KEY"));
- var bing = new WebSearchEngineSkill(bingConnector);
- var search = kernel.ImportSkill(bing, "bing");
+ var bing = new WebSearchEnginePlugin(bingConnector);
+ var search = kernel.ImportFunctions(bing, "bing");
// var planner = new ActionPlanner();
var planner = new SequentialPlanner(kernel);
var plan = await planner.CreatePlanAsync(message);
- await plan.InvokeAsync();
+ await kernel.RunAsync(plan);
}
private readonly ILogger _logger;
diff --git a/apps/SKonsole/Commands/PromptChatCommand.cs b/apps/SKonsole/Commands/PromptChatCommand.cs
index d2a12c9..edc4328 100644
--- a/apps/SKonsole/Commands/PromptChatCommand.cs
+++ b/apps/SKonsole/Commands/PromptChatCommand.cs
@@ -2,9 +2,9 @@
using System.Text;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.AI;
using Microsoft.SemanticKernel.Orchestration;
using Microsoft.SemanticKernel.SemanticFunctions;
-using Microsoft.SemanticKernel.SkillDefinition;
using SKonsole.Utils;
using Spectre.Console;
@@ -46,16 +46,19 @@ private static async Task RunPromptChat(CancellationToken token, ILogger logger)
AI:
";
- var promptConfig = new PromptTemplateConfig
- {
- Completion =
+ var promptConfig = new PromptTemplateConfig();
+ promptConfig.ModelSettings.Add(
+ new AIRequestSettings()
{
- MaxTokens = 2000,
- Temperature = 0.7,
- TopP = 0.5,
- StopSequences = new List { "Human:", "AI:" },
+ ExtensionData = new Dictionary()
+ {
+ { "Temperature", 0.7 },
+ { "TopP", 0.5 },
+ { "MaxTokens", 2000 },
+ { "StopSequences", new List { "Human:", "AI:" } }
+ }
}
- };
+ );
var promptTemplate = new PromptTemplate(SkPrompt, promptConfig, kernel);
var functionConfig = new SemanticFunctionConfig(promptConfig, promptTemplate);
var chatFunction = kernel.RegisterSemanticFunction("PromptBot", "Chat", functionConfig);
@@ -74,7 +77,7 @@ private static async Task RunChat(IKernel kernel, ILogger? logger, ISKFunction c
var botMessage = await kernel.RunAsync(contextVariables, chatFunction);
var userMessage = string.Empty;
- void HorizontalRule(string title, string style = "white bold")
+ static void HorizontalRule(string title, string style = "white bold")
{
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule($"[{style}]{title}[/]").RuleStyle("grey").LeftJustified());
@@ -85,7 +88,7 @@ void HorizontalRule(string title, string style = "white bold")
{
HorizontalRule("AI", "green bold");
AnsiConsole.Foreground = ConsoleColor.Green;
- AnsiConsole.WriteLine(botMessage.ToString());
+ AnsiConsole.WriteLine(botMessage?.ToString() ?? "NO MESSAGE FROM BOT");
AnsiConsole.ResetColors();
HorizontalRule("User");
diff --git a/apps/SKonsole/Commands/StepwisePlannerCommand.cs b/apps/SKonsole/Commands/StepwisePlannerCommand.cs
index 97faee5..28429ae 100644
--- a/apps/SKonsole/Commands/StepwisePlannerCommand.cs
+++ b/apps/SKonsole/Commands/StepwisePlannerCommand.cs
@@ -4,11 +4,11 @@
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Orchestration;
-using Microsoft.SemanticKernel.Planning;
-using Microsoft.SemanticKernel.SkillDefinition;
-using Microsoft.SemanticKernel.Skills.Core;
-using Microsoft.SemanticKernel.Skills.Web;
-using Microsoft.SemanticKernel.Skills.Web.Bing;
+using Microsoft.SemanticKernel.Planners;
+using Microsoft.SemanticKernel.Plugins.Core;
+using Microsoft.SemanticKernel.Plugins.Web;
+using Microsoft.SemanticKernel.Plugins.Web.Bing;
+using SKonsole.Skills;
using SKonsole.Utils;
using Spectre.Console;
@@ -38,7 +38,7 @@ private static async Task RunCreatePlan(CancellationToken token, ILogger logger,
IKernel kernel = LoadOptionSet(optionSet);
var stepKernel = KernelProvider.Instance.Get();
- var functions = stepKernel.ImportSkill(new StepwiseSkill(kernel), "stepwise");
+ var functions = stepKernel.ImportFunctions(new StepwiseSkill(kernel), "stepwise");
await RunChat(stepKernel, null, functions["RespondTo"]).ConfigureAwait(false);
}
@@ -50,31 +50,31 @@ private static IKernel LoadOptionSet(string optionSet)
if (optionSet.Contains("bing"))
{
var bingConnector = new BingConnector(Configuration.ConfigVar("BING_API_KEY"));
- var bing = new WebSearchEngineSkill(bingConnector);
- var search = kernel.ImportSkill(bing, "bing");
+ var bing = new WebSearchEnginePlugin(bingConnector);
+ var search = kernel.ImportFunctions(bing, "bing");
}
if (optionSet.Contains("++"))
{
- kernel.ImportSkill(new TimeSkill(), "time");
- kernel.ImportSkill(new ConversationSummarySkill(kernel), "summary");
- kernel.ImportSkill(new FileIOSkill(), "file");
+ kernel.ImportFunctions(new TimePlugin(), "time");
+ kernel.ImportFunctions(new ConversationSummaryPlugin(kernel), "summary");
+ kernel.ImportFunctions(new SuperFileIOPlugin(), "file");
}
else
{
if (optionSet.Contains("time"))
{
- kernel.ImportSkill(new TimeSkill(), "time");
+ kernel.ImportFunctions(new TimePlugin(), "time");
}
if (optionSet.Contains("summary"))
{
- kernel.ImportSkill(new ConversationSummarySkill(kernel), "summary");
+ kernel.ImportFunctions(new ConversationSummaryPlugin(kernel), "summary");
}
if (optionSet.Contains("file"))
{
- kernel.ImportSkill(new FileIOSkill(), "file");
+ kernel.ImportFunctions(new SuperFileIOPlugin(), "file");
}
}
@@ -90,7 +90,7 @@ public StepwiseSkill(IKernel kernel)
}
[SKFunction, Description("Respond to a message.")]
- public async Task RespondTo(string message, string history)
+ public async Task RespondTo(string message, string history)
{
var planner = new StepwisePlanner(this._kernel);
@@ -103,10 +103,24 @@ public async Task RespondTo(string message, string history)
// var result = await plan.InvokeAsync();
// Option 3 - Respond to the history with prompt
- var plan2 = planner.CreatePlan($"{history}\n---\nGiven the conversation history, respond to the most recent message.");
- var result = await plan2.InvokeAsync();
+ var plan = planner.CreatePlan($"{history}\n---\nGiven the conversation history, respond to the most recent message.");
+ var result = await this._kernel.RunAsync(plan);
- return result;
+ // Extract metadata and result string into new SKContext -- Is there a better way?
+ var functionResult = result?.FunctionResults?.FirstOrDefault();
+ if (functionResult == null)
+ {
+ return null;
+ }
+
+ var context = this._kernel.CreateNewContext();
+ context.Variables.Update(functionResult.GetValue());
+ foreach (var key in functionResult.Metadata.Keys)
+ {
+ context.Variables.Set(key, functionResult.Metadata[key]?.ToString());
+ }
+
+ return context;
}
}
@@ -119,13 +133,11 @@ private static async Task RunChat(IKernel kernel, ILogger? logger, ISKFunction c
var history = string.Empty;
contextVariables.Set("history", history);
- var botMessage = kernel.CreateNewContext();
- botMessage.Variables.Update("Hello!");
- //var botMessage = await kernel.RunAsync(contextVariables, chatFunction);
+ KernelResult botMessage = KernelResult.FromFunctionResults("Hello!", new List());
var userMessage = string.Empty;
- void HorizontalRule(string title, string style = "white bold")
+ static void HorizontalRule(string title, string style = "white bold")
{
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule($"[{style}]{title}[/]").RuleStyle("grey").LeftJustified());
@@ -134,9 +146,10 @@ void HorizontalRule(string title, string style = "white bold")
while (userMessage != "exit")
{
- if (botMessage.Variables.TryGetValue("skillCount", out string? skillCount) && skillCount != "0 ()")
+ var functionResult = botMessage.FunctionResults.FirstOrDefault();
+ if (functionResult is not null && functionResult.TryGetMetadataValue("functionCount", out string? functionCount) && functionCount != "0 ()")
{
- HorizontalRule($"AI - {skillCount}", "green bold");
+ HorizontalRule($"AI - {functionCount}", "green bold");
}
else
{
@@ -144,7 +157,15 @@ void HorizontalRule(string title, string style = "white bold")
}
AnsiConsole.Foreground = ConsoleColor.Green;
- AnsiConsole.WriteLine(botMessage.ToString());
+ var message = botMessage.GetValue() ?? string.Empty;
+ if (message.Contains("Result not found"))
+ {
+ if (functionResult is not null && functionResult.TryGetMetadataValue("stepsTaken", out string? stepsTaken))
+ {
+ message += $"\n{stepsTaken}";
+ }
+ }
+ AnsiConsole.WriteLine(message);
AnsiConsole.ResetColors();
HorizontalRule("User");
@@ -155,11 +176,11 @@ void HorizontalRule(string title, string style = "white bold")
break;
}
- history += $"AI: {botMessage}\nHuman: {userMessage} \n";
+ history += $"AI: {botMessage.GetValue()}\nHuman: {userMessage} \n";
contextVariables.Set("history", history);
contextVariables.Set("message", userMessage);
- botMessage = await AnsiConsole.Progress()
+ var kernelResult = await AnsiConsole.Progress()
.AutoClear(true)
.Columns(new ProgressColumn[]
{
@@ -175,6 +196,7 @@ void HorizontalRule(string title, string style = "white bold")
task.StopTask();
return result;
});
+ botMessage = kernelResult ?? botMessage;
}
}
diff --git a/apps/SKonsole/KernelProvider.cs b/apps/SKonsole/KernelProvider.cs
index 77f3d27..24e2679 100644
--- a/apps/SKonsole/KernelProvider.cs
+++ b/apps/SKonsole/KernelProvider.cs
@@ -14,22 +14,16 @@ public IKernel Get()
{
var kernelBuilder = Kernel.Builder;
- switch (Configuration.ConfigOption(ConfigConstants.LLM_PROVIDER))
+ kernelBuilder = Configuration.ConfigOption(ConfigConstants.LLM_PROVIDER) switch
{
- case ConfigConstants.OpenAI:
- kernelBuilder = kernelBuilder.WithOpenAIChatCompletionService(
- Configuration.ConfigVar(ConfigConstants.OPENAI_CHAT_MODEL_ID),
- Configuration.ConfigVar(ConfigConstants.OPENAI_API_KEY));
- break;
- case ConfigConstants.AzureOpenAI:
- default:
- kernelBuilder = kernelBuilder.WithAzureChatCompletionService(
- Configuration.ConfigVar(ConfigConstants.AZURE_OPENAI_CHAT_DEPLOYMENT_NAME),
- Configuration.ConfigVar(ConfigConstants.AZURE_OPENAI_API_ENDPOINT),
- Configuration.ConfigVar(ConfigConstants.AZURE_OPENAI_API_KEY));
- break;
- }
-
+ ConfigConstants.OpenAI => kernelBuilder.WithOpenAIChatCompletionService(
+ Configuration.ConfigVar(ConfigConstants.OPENAI_CHAT_MODEL_ID),
+ Configuration.ConfigVar(ConfigConstants.OPENAI_API_KEY)),
+ _ => kernelBuilder.WithAzureChatCompletionService(
+ Configuration.ConfigVar(ConfigConstants.AZURE_OPENAI_CHAT_DEPLOYMENT_NAME),
+ Configuration.ConfigVar(ConfigConstants.AZURE_OPENAI_API_ENDPOINT),
+ Configuration.ConfigVar(ConfigConstants.AZURE_OPENAI_API_KEY)),
+ };
var _kernel = kernelBuilder
.WithRetryBasic(new()
{
diff --git a/apps/SKonsole/Program.cs b/apps/SKonsole/Program.cs
index a434161..458b9fe 100644
--- a/apps/SKonsole/Program.cs
+++ b/apps/SKonsole/Program.cs
@@ -6,13 +6,14 @@
Console.OutputEncoding = Encoding.Unicode;
-var rootCommand = new RootCommand();
-
-rootCommand.Add(new ConfigCommand(ConfigurationProvider.Instance));
-rootCommand.Add(new CommitCommand(ConfigurationProvider.Instance));
-rootCommand.Add(new PRCommand(ConfigurationProvider.Instance));
-rootCommand.Add(new PlannerCommand(ConfigurationProvider.Instance));
-rootCommand.Add(new StepwisePlannerCommand(ConfigurationProvider.Instance));
-rootCommand.Add(new PromptChatCommand(ConfigurationProvider.Instance));
+var rootCommand = new RootCommand
+{
+ new ConfigCommand(ConfigurationProvider.Instance),
+ new CommitCommand(ConfigurationProvider.Instance),
+ new PRCommand(ConfigurationProvider.Instance),
+ new PlannerCommand(ConfigurationProvider.Instance),
+ new StepwisePlannerCommand(ConfigurationProvider.Instance),
+ new PromptChatCommand(ConfigurationProvider.Instance)
+};
return await rootCommand.InvokeAsync(args);
diff --git a/apps/SKonsole/SKonsole.csproj b/apps/SKonsole/SKonsole.csproj
index a3d319c..c5a05bf 100644
--- a/apps/SKonsole/SKonsole.csproj
+++ b/apps/SKonsole/SKonsole.csproj
@@ -17,8 +17,8 @@
-
-
+
+
diff --git a/apps/SKonsole/Skills/EmailSkill.cs b/apps/SKonsole/Skills/EmailSkill.cs
index 20127de..328f912 100644
--- a/apps/SKonsole/Skills/EmailSkill.cs
+++ b/apps/SKonsole/Skills/EmailSkill.cs
@@ -1,7 +1,7 @@
using System.ComponentModel;
using Microsoft.Extensions.Logging;
+using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Orchestration;
-using Microsoft.SemanticKernel.SkillDefinition;
namespace SKonsole.Skills;
diff --git a/apps/SKonsole/Skills/GitSkill.cs b/apps/SKonsole/Skills/GitSkill.cs
index b296dc7..7a23768 100644
--- a/apps/SKonsole/Skills/GitSkill.cs
+++ b/apps/SKonsole/Skills/GitSkill.cs
@@ -1,7 +1,7 @@
using System.ComponentModel;
using System.Diagnostics;
+using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Orchestration;
-using Microsoft.SemanticKernel.SkillDefinition;
namespace SKonsole.Skills;
diff --git a/apps/SKonsole/Skills/SuperFileIOPlugin.cs b/apps/SKonsole/Skills/SuperFileIOPlugin.cs
new file mode 100644
index 0000000..0481746
--- /dev/null
+++ b/apps/SKonsole/Skills/SuperFileIOPlugin.cs
@@ -0,0 +1,89 @@
+
+using System.ComponentModel;
+using System.Text;
+using Microsoft.SemanticKernel;
+
+namespace SKonsole.Skills;
+
+public class SuperFileIOPlugin
+{
+ ///
+ /// Read a file
+ ///
+ ///
+ /// {{file.readAsync $path }} => "hello world"
+ ///
+ /// Source file
+ /// File content
+ [SKFunction, Description("Read a file")]
+ public async Task ReadAsync([Description("Source file")] string path)
+ {
+ path = string.IsNullOrEmpty(path) ? Directory.GetCurrentDirectory() : path;
+ using var reader = File.OpenText(path);
+ return await reader.ReadToEndAsync().ConfigureAwait(false);
+ }
+
+ [SKFunction, Description("List files in a directory")]
+ public string List([Description("Source directory")] string path)
+ {
+ path = string.IsNullOrEmpty(path) ? Directory.GetCurrentDirectory() : path;
+ var files = Directory.GetFiles(path);
+ return string.Join("\n", files);
+ }
+
+ [SKFunction, Description("List directories in a directory")]
+ public string ListDirs([Description("Source directory")] string path)
+ {
+ path = string.IsNullOrEmpty(path) ? Directory.GetCurrentDirectory() : path;
+ var files = Directory.GetFiles(path);
+ return string.Join("\n", files);
+ }
+
+ [SKFunction, Description("Search files in a directory")]
+ public string Search([Description("Source directory")] string path, [Description("Search pattern")] string pattern)
+ {
+ path = string.IsNullOrEmpty(path) ? Directory.GetCurrentDirectory() : path;
+ var files = Directory.GetFiles(path, pattern);
+ return string.Join("\n", files);
+ }
+
+ [SKFunction, Description("Search files in a directory, recursively")]
+ public string SearchAll([Description("Source directory")] string path, [Description("Search pattern")] string pattern)
+ {
+ path = string.IsNullOrEmpty(path) ? Directory.GetCurrentDirectory() : path;
+ var files = Directory.GetFiles(path, pattern, SearchOption.AllDirectories);
+ return string.Join("\n", files);
+ }
+
+ [SKFunction, Description("Get current directory")]
+ public string CurrentDirectory()
+ {
+ return Directory.GetCurrentDirectory();
+ }
+
+ ///
+ /// Write a file
+ ///
+ ///
+ /// {{file.writeAsync}}
+ ///
+ /// The destination file path
+ /// The file content to write
+ /// An awaitable task
+ [SKFunction, Description("Write a file")]
+ public async Task WriteAsync(
+ [Description("Destination file")] string path,
+ [Description("File content")] string content)
+ {
+ path = string.IsNullOrEmpty(path) ? Directory.GetCurrentDirectory() : path;
+ byte[] text = Encoding.UTF8.GetBytes(content);
+ if (File.Exists(path) && File.GetAttributes(path).HasFlag(FileAttributes.ReadOnly))
+ {
+ // Most environments will throw this with OpenWrite, but running inside docker on Linux will not.
+ throw new UnauthorizedAccessException($"File is read-only: {path}");
+ }
+
+ using var writer = File.OpenWrite(path);
+ await writer.WriteAsync(text, 0, text.Length).ConfigureAwait(false);
+ }
+}
diff --git a/apps/SKonsole/Skills/WriterSkill.cs b/apps/SKonsole/Skills/WriterSkill.cs
index 79da1ba..8a38449 100644
--- a/apps/SKonsole/Skills/WriterSkill.cs
+++ b/apps/SKonsole/Skills/WriterSkill.cs
@@ -1,5 +1,5 @@
using Microsoft.SemanticKernel;
-using Microsoft.SemanticKernel.SkillDefinition;
+using Microsoft.SemanticKernel.AI;
namespace SKonsole.Skills;
@@ -13,11 +13,17 @@ public WriterSkill(IKernel kernel)
{
this._funnyPoemFunction = kernel.CreateSemanticFunction(
FunnyPoemDefinition,
- skillName: nameof(WriterSkill),
+ pluginName: nameof(WriterSkill),
description: "Given a input topic or description or list, write a funny poem.",
- maxTokens: MaxTokens,
- temperature: 0.1,
- topP: 0.5);
+ requestSettings: new AIRequestSettings()
+ {
+ ExtensionData = new Dictionary()
+ {
+ { "Temperature", 0.1 },
+ { "TopP", 0.5 },
+ { "MaxTokens", MaxTokens }
+ }
+ });
}
private const string FunnyPoemDefinition =
diff --git a/apps/SKonsole/Utils/Logging.cs b/apps/SKonsole/Utils/Logging.cs
index 635d256..142cd35 100644
--- a/apps/SKonsole/Utils/Logging.cs
+++ b/apps/SKonsole/Utils/Logging.cs
@@ -10,11 +10,12 @@ internal static ILoggerFactory GetFactory()
{
builder
.SetMinimumLevel(LogLevel.Information)
+ // .AddFilter("Microsoft.SemanticKernel.Planners.StepwisePlanner", LogLevel.Information) // Toggle to see chain of thought
.AddFilter("Microsoft", LogLevel.Error)
.AddFilter("AzureChatCompletion", LogLevel.Error)
.AddFilter("System", LogLevel.Error)
.AddFilter("SKonsole", LogLevel.Information)
- .AddConsole();
+ .AddSpectreConsole();
});
}
}
diff --git a/apps/SKonsole/Utils/SpectreConsoleExtensions.cs b/apps/SKonsole/Utils/SpectreConsoleExtensions.cs
index 2ac72c2..8811a97 100644
--- a/apps/SKonsole/Utils/SpectreConsoleExtensions.cs
+++ b/apps/SKonsole/Utils/SpectreConsoleExtensions.cs
@@ -7,7 +7,7 @@ public static TextPrompt IsSecret(this TextPrompt obj, bool IsSecret, c
{
if (obj == null)
{
- throw new ArgumentNullException("obj");
+ throw new ArgumentNullException(nameof(obj));
}
obj.IsSecret = IsSecret;
diff --git a/apps/SKonsole/Utils/SpectreConsoleLoggerProvider.cs b/apps/SKonsole/Utils/SpectreConsoleLoggerProvider.cs
new file mode 100644
index 0000000..423af7f
--- /dev/null
+++ b/apps/SKonsole/Utils/SpectreConsoleLoggerProvider.cs
@@ -0,0 +1,94 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Spectre.Console;
+
+namespace SKonsole.Utils;
+
+public sealed class SpectreConsoleLoggerProvider : ILoggerProvider
+{
+ public ILogger CreateLogger(string categoryName)
+ {
+ return new SpectreConsoleLogger(categoryName);
+ }
+
+ public void Dispose() { }
+}
+
+public sealed class SpectreConsoleLogger : ILogger, IDisposable
+{
+ private readonly string _categoryName;
+
+ public SpectreConsoleLogger(string categoryName)
+ {
+ this._categoryName = categoryName;
+ }
+
+ public IDisposable BeginScope(TState state) where TState : notnull => this;
+
+ public void Dispose()
+ {
+ return;
+ }
+
+ public bool IsEnabled(LogLevel logLevel) => true;
+
+ public void Log(
+ LogLevel logLevel,
+ EventId eventId,
+ TState state,
+ Exception? exception,
+ Func formatter)
+ {
+ if (!this.IsEnabled(logLevel))
+ {
+ return;
+ }
+
+ var message = formatter(state, exception);
+
+ if (this._categoryName.EndsWith(".StepwisePlanner"))
+ {
+ var splitIndex = message.IndexOf(':');
+ if (splitIndex == -1)
+ {
+ AnsiConsole.MarkupLineInterpolated($"[bold red]{message}[/]");
+ return;
+ }
+
+ var label = message.Substring(0, splitIndex);
+ var rest = message.Substring(splitIndex + 1);
+
+ if (label == "Action")
+ {
+ if (rest.Contains("No action to take"))
+ {
+ return;
+ }
+
+ AnsiConsole.MarkupLineInterpolated($"[bold blue]{label}:[/] {rest}");
+ return;
+ }
+
+ // if final answer, color is green
+ if (label == "Thought" && rest.StartsWith("Final answer:"))
+ {
+ AnsiConsole.MarkupLineInterpolated($"[bold green]{label}:[/] {rest}");
+ return;
+ }
+
+ AnsiConsole.MarkupLineInterpolated($"[bold yellow]{label}:[/] {rest}");
+ return;
+ }
+
+ AnsiConsole.MarkupLineInterpolated($"[bold]{logLevel}[/]: {this._categoryName}: {message}");
+ }
+}
+
+public static class SpectreConsoleLoggingExtensions
+{
+ public static ILoggingBuilder AddSpectreConsole(this ILoggingBuilder builder)
+ {
+ builder.Services.AddSingleton();
+ return builder;
+ }
+}
diff --git a/skills/CondenseSkill/CondenseSkill.cs b/skills/CondenseSkill/CondenseSkill.cs
index 1e1a417..0161296 100644
--- a/skills/CondenseSkill/CondenseSkill.cs
+++ b/skills/CondenseSkill/CondenseSkill.cs
@@ -6,7 +6,6 @@
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Orchestration;
-using Microsoft.SemanticKernel.SkillDefinition;
using Microsoft.SemanticKernel.Text;
namespace CondenseSkillLib;
@@ -23,7 +22,7 @@ public CondenseSkill(IKernel kernel)
{
// Load semantic skill defined with prompt templates
var folder = CondenseSkillPath();
- var condenseSkill = kernel.ImportSemanticSkillFromDirectory(folder, SEMANTIC_FUNCTION_PATH);
+ var condenseSkill = kernel.ImportSemanticFunctionsFromDirectory(folder, SEMANTIC_FUNCTION_PATH);
this._logger = kernel.LoggerFactory.CreateLogger();
}
catch (Exception e)
@@ -41,7 +40,7 @@ public async Task Condense(
string separator = "",
CancellationToken cancellationToken = default)
{
- var condenser = context.Skills.GetFunction(SEMANTIC_FUNCTION_PATH, "Condenser");
+ var condenser = context.Functions.GetFunction(SEMANTIC_FUNCTION_PATH, "Condenser");
List lines = TextChunker.SplitPlainTextLines(input, CHUNK_SIZE / 8, EnglishRobertaTokenizer.Counter);
List paragraphs = TextChunker.SplitPlainTextParagraphs(lines, CHUNK_SIZE, 100, tokenCounter: EnglishRobertaTokenizer.Counter);
@@ -50,8 +49,8 @@ public async Task Condense(
foreach (var paragraph in paragraphs)
{
context.Variables.Update(paragraph + separator);
- context = await condenser.InvokeAsync(context, cancellationToken: cancellationToken);
- condenseResult.Add(context.Result);
+ var result = await context.Runner.RunAsync(condenser, context.Variables, cancellationToken: cancellationToken);
+ condenseResult.Add(result.GetValue());
}
if (paragraphs.Count <= 1)
diff --git a/skills/PRSkill/PullRequestSkill.cs b/skills/PRSkill/PullRequestSkill.cs
index ad7b845..d4d0625 100644
--- a/skills/PRSkill/PullRequestSkill.cs
+++ b/skills/PRSkill/PullRequestSkill.cs
@@ -5,9 +5,9 @@
using CondenseSkillLib;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
+using Microsoft.SemanticKernel.AI;
using Microsoft.SemanticKernel.AI.TextCompletion;
using Microsoft.SemanticKernel.Orchestration;
-using Microsoft.SemanticKernel.SkillDefinition;
using PRSkill.Utils;
namespace PRSkill;
@@ -20,9 +20,9 @@ public static async Task RollingChunkProcess(this ISKFunction func, L
foreach (var chunk in chunkedInput)
{
context.Variables.Update(chunk);
- context = await func.InvokeAsync(context);
+ var result = await context.Runner.RunAsync(func, context.Variables);
- context.Variables.Set("previousresults", context.Result);
+ context.Variables.Set("previousresults", result.GetValue());
}
return context;
@@ -34,9 +34,9 @@ public static async Task CondenseChunkProcess(this ISKFunction func,
foreach (var chunk in chunkedInput)
{
context.Variables.Update(chunk);
- context = await func.InvokeAsync(context);
+ var result = await context.Runner.RunAsync(func, context.Variables);
- results.Add(context.Result);
+ results.Add(result.GetValue());
}
if (chunkedInput.Count <= 1)
@@ -56,9 +56,9 @@ public static async Task AggregateChunkProcess(this ISKFunction func,
foreach (var chunk in chunkedInput)
{
context.Variables.Update(chunk);
- context = await func.InvokeAsync(context);
+ var result = await context.Runner.RunAsync(func, context.Variables);
- results.Add(context.Result);
+ results.Add(result.GetValue());
}
context.Variables.Update(string.Join("\n", results));
@@ -82,13 +82,13 @@ public PullRequestSkill(IKernel kernel)
{
// Load semantic skill defined with prompt templates
var folder = PRSkillsPath();
- var PRSkill = kernel.ImportSemanticSkillFromDirectory(folder, SEMANTIC_FUNCTION_PATH);
+ var PRSkill = kernel.ImportSemanticFunctionsFromDirectory(folder, SEMANTIC_FUNCTION_PATH);
this._condenseSkill = new CondenseSkill(kernel);
this._kernel = Kernel.Builder
.WithAIService(null, new RedirectTextCompletion(), true)
.Build();
- this._kernel.ImportSemanticSkillFromDirectory(folder, SEMANTIC_FUNCTION_PATH);
+ this._kernel.ImportSemanticFunctionsFromDirectory(folder, SEMANTIC_FUNCTION_PATH);
this._logger = this._kernel.LoggerFactory.CreateLogger();
}
@@ -106,7 +106,7 @@ public async Task GeneratePullRequestFeedback(
{
this._logger.LogTrace("GeneratePullRequestFeedback called");
- var prFeedbackGenerator = context.Skills.GetFunction(SEMANTIC_FUNCTION_PATH, "PullRequestFeedbackGenerator");
+ var prFeedbackGenerator = context.Functions.GetFunction(SEMANTIC_FUNCTION_PATH, "PullRequestFeedbackGenerator");
var chunkedInput = CommitChunker.ChunkCommitInfo(input, CHUNK_SIZE);
return await prFeedbackGenerator.AggregateChunkProcess(chunkedInput, context);
}
@@ -120,10 +120,10 @@ public async Task GenerateCommitMessage(
{
this._logger.LogTrace("GenerateCommitMessage called");
- var commitGenerator = context.Skills.GetFunction(SEMANTIC_FUNCTION_PATH, "CommitMessageGenerator");
+ var commitGenerator = context.Functions.GetFunction(SEMANTIC_FUNCTION_PATH, "CommitMessageGenerator");
- var commitGeneratorCapture = this._kernel.Skills.GetFunction(SEMANTIC_FUNCTION_PATH, "CommitMessageGenerator");
- var prompt = (await commitGeneratorCapture.InvokeAsync(cancellationToken: cancellationToken)).Result;
+ var commitGeneratorCapture = this._kernel.Functions.GetFunction(SEMANTIC_FUNCTION_PATH, "CommitMessageGenerator");
+ var prompt = (await this._kernel.RunAsync(commitGeneratorCapture, cancellationToken: cancellationToken)).GetValue();
var chunkedInput = CommitChunker.ChunkCommitInfo(input, CHUNK_SIZE);
return await commitGenerator.CondenseChunkProcess(this._condenseSkill, chunkedInput, prompt, context, "CommitMessageResult");
@@ -136,7 +136,7 @@ public async Task GeneratePR_Rolling(
SKContext context,
CancellationToken cancellationToken = default)
{
- var prGenerator_Rolling = context.Skills.GetFunction(SEMANTIC_FUNCTION_PATH, "PullRequestDescriptionGenerator_Rolling");
+ var prGenerator_Rolling = context.Functions.GetFunction(SEMANTIC_FUNCTION_PATH, "PullRequestDescriptionGenerator_Rolling");
var chunkedInput = CommitChunker.ChunkCommitInfo(input, CHUNK_SIZE);
return await prGenerator_Rolling.RollingChunkProcess(chunkedInput, context);
}
@@ -148,12 +148,12 @@ public async Task GeneratePR(
SKContext context,
CancellationToken cancellationToken = default)
{
- var prGenerator = context.Skills.GetFunction(SEMANTIC_FUNCTION_PATH, "PullRequestDescriptionGenerator");
+ var prGenerator = context.Functions.GetFunction(SEMANTIC_FUNCTION_PATH, "PullRequestDescriptionGenerator");
- var prGeneratorCapture = this._kernel.Skills.GetFunction(SEMANTIC_FUNCTION_PATH, "PullRequestDescriptionGenerator");
+ var prGeneratorCapture = this._kernel.Functions.GetFunction(SEMANTIC_FUNCTION_PATH, "PullRequestDescriptionGenerator");
var contextVariablesWithoutInput = context.Variables.Clone();
contextVariablesWithoutInput.Set("input", "");
- var prompt = (await prGeneratorCapture.InvokeAsync(variables: contextVariablesWithoutInput, cancellationToken: cancellationToken)).Result;
+ var prompt = (await this._kernel.RunAsync(prGeneratorCapture, contextVariablesWithoutInput, cancellationToken: cancellationToken)).GetValue();
var chunkedInput = CommitChunker.ChunkCommitInfo(input, CHUNK_SIZE);
return await prGenerator.CondenseChunkProcess(this._condenseSkill, chunkedInput, prompt, context, "PullRequestDescriptionResult");
@@ -189,12 +189,12 @@ static bool SearchPath(string pathToFind, out string result, int maxAttempts = 1
public class RedirectTextCompletion : ITextCompletion
{
- Task> ITextCompletion.GetCompletionsAsync(string text, CompleteRequestSettings requestSettings, CancellationToken cancellationToken)
+ Task> ITextCompletion.GetCompletionsAsync(string text, AIRequestSettings requestSettings, CancellationToken cancellationToken)
{
return Task.FromResult>(new List { new RedirectTextCompletionResult(text) });
}
- IAsyncEnumerable ITextCompletion.GetStreamingCompletionsAsync(string text, CompleteRequestSettings requestSettings, CancellationToken cancellationToken)
+ IAsyncEnumerable ITextCompletion.GetStreamingCompletionsAsync(string text, AIRequestSettings requestSettings, CancellationToken cancellationToken)
{
throw new NotImplementedException(); // TODO
}
diff --git a/skills/PRSkill/Utils/CommitParser.cs b/skills/PRSkill/Utils/CommitParser.cs
index 341773a..62e4515 100644
--- a/skills/PRSkill/Utils/CommitParser.cs
+++ b/skills/PRSkill/Utils/CommitParser.cs
@@ -47,7 +47,7 @@ internal static class StringEx
}
var fileDiffMetadata = fileDiffMatch.Value;
- var nextMatch = j == fileDiffMatches.Count - 1 || (fileDiffMatches[j + 1].Index) >= inputEnd ? inputEnd : fileDiffMatches[j + 1].Index;
+ var nextMatch = j == fileDiffMatches.Count - 1 || fileDiffMatches[j + 1].Index >= inputEnd ? inputEnd : fileDiffMatches[j + 1].Index;
var fileDiff = input[(fileDiffMatch.Index + fileDiffMatch.Length)..nextMatch];
fileDiffChunks.Add((fileDiffMetadata, fileDiff));
}