From 8c899012134ab327dd82a1e963737ed0a5d187f8 Mon Sep 17 00:00:00 2001 From: Chris <66376200+crickman@users.noreply.github.com> Date: Wed, 8 Nov 2023 15:59:44 -0800 Subject: [PATCH] Replace "Skills" term, as appropriate. (#587) ### Motivation and Context Since late May 2023, we've been transitioning away from the term `Skills `in favor of `Plugins` in the semantic-kernel ecosystem. This completes that transition for chat-copiilot. > NOTE: There is one definition where the `skill` term cannot be replaced since its linked to the Plan class definition in semantic-kernel. ![image](https://github.com/microsoft/chat-copilot/assets/66376200/bc0dd9ba-297e-468f-8078-fb8b187335f8) ![image](https://github.com/microsoft/chat-copilot/assets/66376200/2079825b-528d-4556-8899-0084ee63abd6) ### Contribution Checklist - [x] The code builds clean without any errors or warnings - [x] The PR follows the [Contribution Guidelines](https://github.com/microsoft/chat-copilot/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/chat-copilot/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone :smile: --- webapi/Controllers/ChatController.cs | 60 +++++++------- webapi/Controllers/ChatHistoryController.cs | 2 +- webapi/CopilotChatWebApi.csproj | 4 +- webapi/Extensions/SemanticKernelExtensions.cs | 42 +++++----- .../Models/Response/PlanExecutionMetadata.cs | 10 +-- webapi/Options/PromptsOptions.cs | 10 +-- .../Chat/ChatPlugin.cs} | 42 +++++----- .../Chat}/CopilotChatPlanner.cs | 4 +- .../Chat/ExternalInformationPlugin.cs} | 80 +++++++++---------- .../Chat}/SemanticChatMemory.cs | 2 +- .../Chat}/SemanticChatMemoryExtractor.cs | 4 +- .../Chat}/SemanticChatMemoryItem.cs | 2 +- .../Chat}/SemanticMemoryRetriever.cs | 4 +- .../OpenApi}/GitHubPlugin/Model/Label.cs | 2 +- .../GitHubPlugin/Model/PullRequest.cs | 2 +- .../OpenApi}/GitHubPlugin/Model/Repo.cs | 2 +- .../OpenApi}/GitHubPlugin/Model/User.cs | 2 +- .../OpenApi}/GitHubPlugin/openapi.json | 0 .../JiraPlugin/Model/CommentAuthor.cs | 2 +- .../JiraPlugin/Model/CommentResponse.cs | 2 +- .../JiraPlugin/Model/IndividualComments.cs | 2 +- .../JiraPlugin/Model/IssueResponse.cs | 2 +- .../JiraPlugin/Model/IssueResponseFIeld.cs | 2 +- .../OpenApi}/JiraPlugin/openapi.json | 0 .../OpenApi}/README.md | 6 +- .../{Skills => Plugins}/Utils/AsyncUtils.cs | 2 +- .../{Skills => Plugins}/Utils/PromptUtils.cs | 2 +- .../{Skills => Plugins}/Utils/TokenUtils.cs | 4 +- webapi/README.md | 54 ++++++------- .../Services/AppInsightsTelemetryService.cs | 6 +- webapi/Services/ITelemetryService.cs | 10 +-- webapi/appsettings.json | 12 +-- .../StepwiseThoughtProcessView.tsx | 4 +- .../open-api-plugins/PluginConnector.tsx | 2 +- .../src/libs/models/PlanExecutionMetadata.ts | 4 +- webapp/src/libs/services/ChatService.ts | 14 ++-- .../redux/features/plugins/PluginsState.ts | 2 +- webapp/tests/testsBasic.ts | 2 +- 38 files changed, 205 insertions(+), 203 deletions(-) rename webapi/{Skills/ChatSkills/ChatSkill.cs => Plugins/Chat/ChatPlugin.cs} (96%) rename webapi/{Skills/ChatSkills => Plugins/Chat}/CopilotChatPlanner.cs (99%) rename webapi/{Skills/ChatSkills/ExternalInformationSkill.cs => Plugins/Chat/ExternalInformationPlugin.cs} (86%) rename webapi/{Skills/ChatSkills => Plugins/Chat}/SemanticChatMemory.cs (96%) rename webapi/{Skills/ChatSkills => Plugins/Chat}/SemanticChatMemoryExtractor.cs (98%) rename webapi/{Skills/ChatSkills => Plugins/Chat}/SemanticChatMemoryItem.cs (95%) rename webapi/{Skills/ChatSkills => Plugins/Chat}/SemanticMemoryRetriever.cs (99%) rename webapi/{Skills/OpenApiPlugins => Plugins/OpenApi}/GitHubPlugin/Model/Label.cs (93%) rename webapi/{Skills/OpenApiPlugins => Plugins/OpenApi}/GitHubPlugin/Model/PullRequest.cs (98%) rename webapi/{Skills/OpenApiPlugins => Plugins/OpenApi}/GitHubPlugin/Model/Repo.cs (92%) rename webapi/{Skills/OpenApiPlugins => Plugins/OpenApi}/GitHubPlugin/Model/User.cs (95%) rename webapi/{Skills/OpenApiPlugins => Plugins/OpenApi}/GitHubPlugin/openapi.json (100%) rename webapi/{Skills/OpenApiPlugins => Plugins/OpenApi}/JiraPlugin/Model/CommentAuthor.cs (90%) rename webapi/{Skills/OpenApiPlugins => Plugins/OpenApi}/JiraPlugin/Model/CommentResponse.cs (92%) rename webapi/{Skills/OpenApiPlugins => Plugins/OpenApi}/JiraPlugin/Model/IndividualComments.cs (92%) rename webapi/{Skills/OpenApiPlugins => Plugins/OpenApi}/JiraPlugin/Model/IssueResponse.cs (95%) rename webapi/{Skills/OpenApiPlugins => Plugins/OpenApi}/JiraPlugin/Model/IssueResponseFIeld.cs (95%) rename webapi/{Skills/OpenApiPlugins => Plugins/OpenApi}/JiraPlugin/openapi.json (100%) rename webapi/{Skills/OpenApiPlugins => Plugins/OpenApi}/README.md (69%) rename webapi/{Skills => Plugins}/Utils/AsyncUtils.cs (97%) rename webapi/{Skills => Plugins}/Utils/PromptUtils.cs (93%) rename webapi/{Skills => Plugins}/Utils/TokenUtils.cs (98%) diff --git a/webapi/Controllers/ChatController.cs b/webapi/Controllers/ChatController.cs index 46ecdf0f2..59e313a36 100644 --- a/webapi/Controllers/ChatController.cs +++ b/webapi/Controllers/ChatController.cs @@ -16,8 +16,8 @@ using CopilotChat.WebApi.Models.Response; using CopilotChat.WebApi.Models.Storage; using CopilotChat.WebApi.Options; +using CopilotChat.WebApi.Plugins.Chat; using CopilotChat.WebApi.Services; -using CopilotChat.WebApi.Skills.ChatSkills; using CopilotChat.WebApi.Storage; using CopilotChat.WebApi.Utilities; using Microsoft.AspNetCore.Http; @@ -51,7 +51,7 @@ public class ChatController : ControllerBase, IDisposable private readonly PlannerOptions _plannerOptions; private readonly IDictionary _plugins; - private const string ChatSkillName = "ChatSkill"; + private const string ChatPluginName = nameof(ChatPlugin); private const string ChatFunctionName = "Chat"; private const string ProcessPlanFunctionName = "ProcessPlan"; private const string GeneratingResponseClientCall = "ReceiveBotResponseStatus"; @@ -74,7 +74,7 @@ public ChatController( } /// - /// Invokes the chat skill to get a response from the bot. + /// Invokes the chat function to get a response from the bot. /// /// Semantic kernel obtained through dependency injection. /// Message Hub that performs the real time relay service. @@ -110,7 +110,7 @@ public async Task ChatAsync( } /// - /// Invokes the chat skill to process and/or execute plan. + /// Invokes the chat function to process and/or execute plan. /// /// Semantic kernel obtained through dependency injection. /// Message Hub that performs the real time relay service. @@ -146,9 +146,9 @@ public async Task ProcessPlanAsync( } /// - /// Invokes given function of ChatSkill. + /// Invokes given function of ChatPlugin. /// - /// Name of the ChatSkill function to invoke. + /// Name of the ChatPlugin function to invoke. /// Semantic kernel obtained through dependency injection. /// Message Hub that performs the real time relay service. /// Planner to use to create function sequences. @@ -187,22 +187,22 @@ private async Task HandleRequest( } // Register plugins that have been enabled - var openApiSkillsAuthHeaders = this.GetPluginAuthHeaders(this.HttpContext.Request.Headers); - await this.RegisterPlannerSkillsAsync(planner, openApiSkillsAuthHeaders, contextVariables); + var openApiPluginAuthHeaders = this.GetPluginAuthHeaders(this.HttpContext.Request.Headers); + await this.RegisterPlannerFunctionsAsync(planner, openApiPluginAuthHeaders, contextVariables); // Register hosted plugins that have been enabled - await this.RegisterPlannerHostedSkillsAsync(planner, chat!.EnabledPlugins); + await this.RegisterPlannerHostedFunctionsUsedAsync(planner, chat!.EnabledPlugins); // Get the function to invoke ISKFunction? function = null; try { - function = kernel.Functions.GetFunction(ChatSkillName, functionName); + function = kernel.Functions.GetFunction(ChatPluginName, functionName); } catch (SKException ex) { - this._logger.LogError("Failed to find {SkillName}/{FunctionName} on server: {Exception}", ChatSkillName, functionName, ex); - return this.NotFound($"Failed to find {ChatSkillName}/{functionName} on server"); + this._logger.LogError("Failed to find {PluginName}/{FunctionName} on server: {Exception}", ChatPluginName, functionName, ex); + return this.NotFound($"Failed to find {ChatPluginName}/{functionName} on server"); } // Run the function. @@ -215,7 +215,7 @@ private async Task HandleRequest( : null; result = await kernel.RunAsync(function!, contextVariables, cts?.Token ?? default); - this._telemetryService.TrackSkillFunction(ChatSkillName, functionName, true); + this._telemetryService.TrackPluginFunction(ChatPluginName, functionName, true); } catch (Exception ex) { @@ -226,11 +226,11 @@ private async Task HandleRequest( return this.StatusCode(StatusCodes.Status504GatewayTimeout, $"The chat {functionName} timed out."); } - this._telemetryService.TrackSkillFunction(ChatSkillName, functionName, false); + this._telemetryService.TrackPluginFunction(ChatPluginName, functionName, false); throw ex; } - AskResult chatSkillAskResult = new() + AskResult chatAskResult = new() { Value = result.GetValue() ?? string.Empty, Variables = contextVariables.Select(v => new KeyValuePair(v.Key, v.Value)) @@ -239,7 +239,7 @@ private async Task HandleRequest( // Broadcast AskResult to all users await messageRelayHubContext.Clients.Group(chatId).SendAsync(GeneratingResponseClientCall, chatId, null); - return this.Ok(chatSkillAskResult); + return this.Ok(chatAskResult); } /// @@ -251,7 +251,7 @@ private Dictionary GetPluginAuthHeaders(IHeaderDictionary header var regex = new Regex("x-sk-copilot-(.*)-auth", RegexOptions.IgnoreCase); // Create a dictionary to store the matched headers and values - var openApiSkillsAuthHeaders = new Dictionary(); + var authHeaders = new Dictionary(); // Loop through the request headers and add the matched ones to the dictionary foreach (var header in headers) @@ -260,28 +260,28 @@ private Dictionary GetPluginAuthHeaders(IHeaderDictionary header if (match.Success) { // Use the first capture group as the key and the header value as the value - openApiSkillsAuthHeaders.Add(match.Groups[1].Value.ToUpperInvariant(), header.Value!); + authHeaders.Add(match.Groups[1].Value.ToUpperInvariant(), header.Value!); } } - return openApiSkillsAuthHeaders; + return authHeaders; } /// - /// Register skills with the planner's kernel. + /// Register functions with the planner's kernel. /// - private async Task RegisterPlannerSkillsAsync(CopilotChatPlanner planner, Dictionary openApiSkillsAuthHeaders, ContextVariables variables) + private async Task RegisterPlannerFunctionsAsync(CopilotChatPlanner planner, Dictionary authHeaders, ContextVariables variables) { - // Register authenticated skills with the planner's kernel only if the request includes an auth header for the skill. + // Register authenticated functions with the planner's kernel only if the request includes an auth header for the plugin. // GitHub - if (openApiSkillsAuthHeaders.TryGetValue("GITHUB", out string? GithubAuthHeader)) + if (authHeaders.TryGetValue("GITHUB", out string? GithubAuthHeader)) { this._logger.LogInformation("Enabling GitHub plugin."); BearerAuthenticationProvider authenticationProvider = new(() => Task.FromResult(GithubAuthHeader)); await planner.Kernel.ImportPluginFunctionsAsync( pluginName: "GitHubPlugin", - filePath: Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "Skills", "OpenApiPlugins/GitHubPlugin/openapi.json"), + filePath: Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "Plugins", "OpenApi/GitHubPlugin/openapi.json"), new OpenApiFunctionExecutionParameters { AuthCallback = authenticationProvider.AuthenticateRequestAsync, @@ -289,7 +289,7 @@ await planner.Kernel.ImportPluginFunctionsAsync( } // Jira - if (openApiSkillsAuthHeaders.TryGetValue("JIRA", out string? JiraAuthHeader)) + if (authHeaders.TryGetValue("JIRA", out string? JiraAuthHeader)) { this._logger.LogInformation("Registering Jira plugin"); var authenticationProvider = new BasicAuthenticationProvider(() => { return Task.FromResult(JiraAuthHeader); }); @@ -297,7 +297,7 @@ await planner.Kernel.ImportPluginFunctionsAsync( await planner.Kernel.ImportPluginFunctionsAsync( pluginName: "JiraPlugin", - filePath: Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "Skills", "OpenApiPlugins/JiraPlugin/openapi.json"), + filePath: Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "Plugins", "OpenApi/JiraPlugin/openapi.json"), new OpenApiFunctionExecutionParameters { AuthCallback = authenticationProvider.AuthenticateRequestAsync, @@ -306,9 +306,9 @@ await planner.Kernel.ImportPluginFunctionsAsync( } // Microsoft Graph - if (openApiSkillsAuthHeaders.TryGetValue("GRAPH", out string? GraphAuthHeader)) + if (authHeaders.TryGetValue("GRAPH", out string? GraphAuthHeader)) { - this._logger.LogInformation("Enabling Microsoft Graph skill(s)."); + this._logger.LogInformation("Enabling Microsoft Graph plugin(s)."); BearerAuthenticationProvider authenticationProvider = new(() => Task.FromResult(GraphAuthHeader)); GraphServiceClient graphServiceClient = this.CreateGraphServiceClient(authenticationProvider.AuthenticateRequestAsync); @@ -325,7 +325,7 @@ await planner.Kernel.ImportPluginFunctionsAsync( { foreach (CustomPlugin plugin in customPlugins) { - if (openApiSkillsAuthHeaders.TryGetValue(plugin.AuthHeaderTag.ToUpperInvariant(), out string? PluginAuthValue)) + if (authHeaders.TryGetValue(plugin.AuthHeaderTag.ToUpperInvariant(), out string? PluginAuthValue)) { // Register the ChatGPT plugin with the planner's kernel. this._logger.LogInformation("Enabling {0} plugin.", plugin.NameForHuman); @@ -373,7 +373,7 @@ private GraphServiceClient CreateGraphServiceClient(AuthenticateRequestAsyncDele return graphServiceClient; } - private async Task RegisterPlannerHostedSkillsAsync(CopilotChatPlanner planner, HashSet enabledPlugins) + private async Task RegisterPlannerHostedFunctionsUsedAsync(CopilotChatPlanner planner, HashSet enabledPlugins) { foreach (string enabledPlugin in enabledPlugins) { diff --git a/webapi/Controllers/ChatHistoryController.cs b/webapi/Controllers/ChatHistoryController.cs index 769db4321..b18220976 100644 --- a/webapi/Controllers/ChatHistoryController.cs +++ b/webapi/Controllers/ChatHistoryController.cs @@ -12,7 +12,7 @@ using CopilotChat.WebApi.Models.Response; using CopilotChat.WebApi.Models.Storage; using CopilotChat.WebApi.Options; -using CopilotChat.WebApi.Skills.Utils; +using CopilotChat.WebApi.Plugins.Utils; using CopilotChat.WebApi.Storage; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; diff --git a/webapi/CopilotChatWebApi.csproj b/webapi/CopilotChatWebApi.csproj index d805e8748..9f0f02583 100644 --- a/webapi/CopilotChatWebApi.csproj +++ b/webapi/CopilotChatWebApi.csproj @@ -84,10 +84,10 @@ PreserveNewest diff --git a/webapi/Extensions/SemanticKernelExtensions.cs b/webapi/Extensions/SemanticKernelExtensions.cs index 7a61faf1c..884a19c66 100644 --- a/webapi/Extensions/SemanticKernelExtensions.cs +++ b/webapi/Extensions/SemanticKernelExtensions.cs @@ -9,8 +9,8 @@ using CopilotChat.WebApi.Hubs; using CopilotChat.WebApi.Models.Response; using CopilotChat.WebApi.Options; +using CopilotChat.WebApi.Plugins.Chat; using CopilotChat.WebApi.Services; -using CopilotChat.WebApi.Skills.ChatSkills; using CopilotChat.WebApi.Storage; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.SignalR; @@ -31,9 +31,9 @@ namespace CopilotChat.WebApi.Extensions; internal static class SemanticKernelExtensions { /// - /// Delegate to register plugins with a Semantic Kernel + /// Delegate to register functions with a Semantic Kernel /// - public delegate Task RegisterSkillsWithKernel(IServiceProvider sp, IKernel kernel); + public delegate Task RegisterFunctionsWithKernel(IServiceProvider sp, IKernel kernel); /// /// Delegate for any complimentary setup of the kernel, i.e., registering custom plugins, etc. @@ -45,7 +45,7 @@ internal static class SemanticKernelExtensions /// Delegate to register plugins with the planner's kernel (i.e., omits plugins not required to generate bot response). /// See webapi/README.md#Add-Custom-Plugin-Registration-to-the-Planner's-Kernel for more details. /// - public delegate Task RegisterSkillsWithPlannerHook(IServiceProvider sp, IKernel kernel); + public delegate Task RegisterFunctionsWithPlannerHook(IServiceProvider sp, IKernel kernel); /// /// Add Semantic Kernel services @@ -61,7 +61,7 @@ public static WebApplicationBuilder AddSemanticKernelServices(this WebApplicatio var provider = sp.GetRequiredService(); var kernel = provider.GetCompletionKernel(); - sp.GetRequiredService()(sp, kernel); + sp.GetRequiredService()(sp, kernel); // If KernelSetupHook is not null, invoke custom kernel setup. sp.GetService()?.Invoke(sp, kernel); @@ -72,7 +72,7 @@ public static WebApplicationBuilder AddSemanticKernelServices(this WebApplicatio builder.Services.AddContentSafety(); // Register plugins - builder.Services.AddScoped(sp => RegisterChatCopilotSkillsAsync); + builder.Services.AddScoped(sp => RegisterChatCopilotFunctionsAsync); // Add any additional setup needed for the kernel. // Uncomment the following line and pass in a custom hook for any complimentary setup of the kernel. @@ -97,7 +97,7 @@ public static WebApplicationBuilder AddPlannerServices(this WebApplicationBuilde var plannerKernel = provider.GetPlannerKernel(); // Invoke custom plugin registration for planner's kernel. - sp.GetService()?.Invoke(sp, plannerKernel); + sp.GetService()?.Invoke(sp, plannerKernel); return new CopilotChatPlanner(plannerKernel, plannerOptions?.Value, sp.GetRequiredService>()); }); @@ -132,27 +132,27 @@ public static IServiceCollection AddKernelSetupHook(this IServiceCollection serv /// /// Register custom hook for registering plugins with the planner's kernel. /// These plugins will be persistent and available to the planner on every request. - /// Transient plugins requiring auth or configured by the webapp should be registered in RegisterPlannerSkillsAsync of ChatController. + /// Transient plugins requiring auth or configured by the webapp should be registered in RegisterPlannerFunctionsAsync of ChatController. /// /// The delegate to register plugins with the planner's kernel. If null, defaults to local runtime plugin registration using RegisterPluginsAsync. - public static IServiceCollection AddPlannerSetupHook(this IServiceCollection services, RegisterSkillsWithPlannerHook? registerPluginsHook = null) + public static IServiceCollection AddPlannerSetupHook(this IServiceCollection services, RegisterFunctionsWithPlannerHook? registerPluginsHook = null) { // Default to local runtime plugin registration. registerPluginsHook ??= RegisterPluginsAsync; // Add the hook to the service collection - services.AddScoped(sp => registerPluginsHook); + services.AddScoped(sp => registerPluginsHook); return services; } /// - /// Register the chat skill with the kernel. + /// Register the chat plugin with the kernel. /// - public static IKernel RegisterChatSkill(this IKernel kernel, IServiceProvider sp) + public static IKernel RegisterChatPlugin(this IKernel kernel, IServiceProvider sp) { - // Chat skill + // Chat plugin kernel.ImportFunctions( - new ChatSkill( + new ChatPlugin( kernel, memoryClient: sp.GetRequiredService(), chatMessageRepository: sp.GetRequiredService(), @@ -162,8 +162,8 @@ public static IKernel RegisterChatSkill(this IKernel kernel, IServiceProvider sp documentImportOptions: sp.GetRequiredService>(), contentSafety: sp.GetService(), planner: sp.GetRequiredService(), - logger: sp.GetRequiredService>()), - nameof(ChatSkill)); + logger: sp.GetRequiredService>()), + nameof(ChatPlugin)); return kernel; } @@ -174,14 +174,14 @@ private static void InitializeKernelProvider(this WebApplicationBuilder builder) } /// - /// Register skills with the main kernel responsible for handling Chat Copilot requests. + /// Register functions with the main kernel responsible for handling Chat Copilot requests. /// - private static Task RegisterChatCopilotSkillsAsync(IServiceProvider sp, IKernel kernel) + private static Task RegisterChatCopilotFunctionsAsync(IServiceProvider sp, IKernel kernel) { - // Chat Copilot skills - kernel.RegisterChatSkill(sp); + // Chat Copilot functions + kernel.RegisterChatPlugin(sp); - // Time skill + // Time plugin kernel.ImportFunctions(new TimePlugin(), nameof(TimePlugin)); return Task.CompletedTask; diff --git a/webapi/Models/Response/PlanExecutionMetadata.cs b/webapi/Models/Response/PlanExecutionMetadata.cs index 449eab83e..2c8256330 100644 --- a/webapi/Models/Response/PlanExecutionMetadata.cs +++ b/webapi/Models/Response/PlanExecutionMetadata.cs @@ -23,10 +23,10 @@ public class PlanExecutionMetadata public string TimeTaken { get; set; } = string.Empty; /// - /// Skills used execution stat. + /// Functions used execution stat. /// - [JsonPropertyName("skillsUsed")] - public string SkillsUsed { get; set; } = string.Empty; + [JsonPropertyName("functionsUsed")] + public string FunctionsUsed { get; set; } = string.Empty; /// /// Planner type. @@ -40,11 +40,11 @@ public class PlanExecutionMetadata [JsonIgnore] public string RawResult { get; set; } = string.Empty; - public PlanExecutionMetadata(string stepsTaken, string timeTaken, string skillsUsed, string rawResult) + public PlanExecutionMetadata(string stepsTaken, string timeTaken, string functionsUsed, string rawResult) { this.StepsTaken = stepsTaken; this.TimeTaken = timeTaken; - this.SkillsUsed = skillsUsed; + this.FunctionsUsed = functionsUsed; this.RawResult = rawResult; } } diff --git a/webapi/Options/PromptsOptions.cs b/webapi/Options/PromptsOptions.cs index 7083578ae..d6be8a336 100644 --- a/webapi/Options/PromptsOptions.cs +++ b/webapi/Options/PromptsOptions.cs @@ -32,7 +32,7 @@ public class PromptsOptions internal double MemoriesResponseContextWeight { get; } = 0.6; /// - /// Weight of information returned from planner (i.e., responses from OpenAPI skills). + /// Weight of information returned from planner (i.e., responses from OpenAPI functions). /// Contextual prompt excludes all the system commands and user intent. /// internal double ExternalInformationContextWeight { get; } = 0.3; @@ -79,7 +79,7 @@ public class PromptsOptions internal string[] SystemAudiencePromptComponents => new string[] { this.SystemAudience, - "{{ChatSkill.ExtractChatHistory}}", + "{{ChatPlugin.ExtractChatHistory}}", this.SystemAudienceContinuation }; @@ -89,7 +89,7 @@ public class PromptsOptions { this.SystemDescription, this.SystemIntent, - "{{ChatSkill.ExtractChatHistory}}", + "{{ChatPlugin.ExtractChatHistory}}", this.SystemIntentContinuation }; @@ -125,7 +125,7 @@ public class PromptsOptions $"{this.LongTermMemoryName} Description:\n{this.LongTermMemoryExtraction}", this.MemoryAntiHallucination, $"Chat Description:\n{this.SystemDescription}", - "{{ChatSkill.ExtractChatHistory}}", + "{{ChatPlugin.ExtractChatHistory}}", this.MemoryContinuation }; @@ -141,7 +141,7 @@ public class PromptsOptions $"{this.WorkingMemoryName} Description:\n{this.WorkingMemoryExtraction}", this.MemoryAntiHallucination, $"Chat Description:\n{this.SystemDescription}", - "{{ChatSkill.ExtractChatHistory}}", + "{{ChatPlugin.ExtractChatHistory}}", this.MemoryContinuation }; diff --git a/webapi/Skills/ChatSkills/ChatSkill.cs b/webapi/Plugins/Chat/ChatPlugin.cs similarity index 96% rename from webapi/Skills/ChatSkills/ChatSkill.cs rename to webapi/Plugins/Chat/ChatPlugin.cs index a14bf42f8..3e5edf283 100644 --- a/webapi/Skills/ChatSkills/ChatSkill.cs +++ b/webapi/Plugins/Chat/ChatPlugin.cs @@ -14,8 +14,8 @@ using CopilotChat.WebApi.Models.Response; using CopilotChat.WebApi.Models.Storage; using CopilotChat.WebApi.Options; +using CopilotChat.WebApi.Plugins.Utils; using CopilotChat.WebApi.Services; -using CopilotChat.WebApi.Skills.Utils; using CopilotChat.WebApi.Storage; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; @@ -32,13 +32,13 @@ using Microsoft.SemanticKernel.TemplateEngine.Basic; using ChatCompletionContextMessages = Microsoft.SemanticKernel.AI.ChatCompletion.ChatHistory; -namespace CopilotChat.WebApi.Skills.ChatSkills; +namespace CopilotChat.WebApi.Plugins.Chat; /// -/// ChatSkill offers a more coherent chat experience by using memories +/// ChatPlugin offers a more coherent chat experience by using memories /// to extract conversation history and user intentions. /// -public class ChatSkill +public class ChatPlugin { /// /// A kernel instance to create a completion function since each invocation @@ -82,9 +82,9 @@ public class ChatSkill private readonly SemanticMemoryRetriever _semanticMemoryRetriever; /// - /// A skill instance to acquire external information. + /// A plugin instance to acquire external information. /// - private readonly ExternalInformationSkill _externalInformationSkill; + private readonly ExternalInformationPlugin _externalInformationPlugin; /// /// Azure content safety moderator. @@ -92,9 +92,9 @@ public class ChatSkill private readonly AzureContentSafety? _contentSafety = null; /// - /// Create a new instance of . + /// Create a new instance of . /// - public ChatSkill( + public ChatPlugin( IKernel kernel, IKernelMemory memoryClient, ChatMessageRepository chatMessageRepository, @@ -121,7 +121,7 @@ public ChatSkill( memoryClient, logger); - this._externalInformationSkill = new ExternalInformationSkill( + this._externalInformationPlugin = new ExternalInformationPlugin( promptOptions, planner, logger); @@ -154,7 +154,7 @@ private async Task ExtractUserIntentAsync(SKContext context, Cancellatio var completionFunction = this._kernel.CreateSemanticFunction( this._promptOptions.SystemIntentExtraction, - pluginName: nameof(ChatSkill), + pluginName: nameof(ChatPlugin), description: "Complete the prompt."); var result = await completionFunction.InvokeAsync( @@ -194,7 +194,7 @@ private async Task ExtractAudienceAsync(SKContext context, CancellationT var completionFunction = this._kernel.CreateSemanticFunction( this._promptOptions.SystemAudienceExtraction, - pluginName: nameof(ChatSkill), + pluginName: nameof(ChatPlugin), description: "Complete the prompt."); var result = await completionFunction.InvokeAsync( @@ -342,7 +342,7 @@ public async Task ChatAsync( } else { - this._logger.LogWarning("ChatSkill.ChatAsync token usage unknown. Ensure token management has been implemented correctly."); + this._logger.LogWarning("ChatPlugin.ChatAsync token usage unknown. Ensure token management has been implemented correctly."); } return context; @@ -436,7 +436,7 @@ await this.SaveNewResponseAsync( chatHistoryString += "\n" + PromptUtils.FormatChatHistoryMessage(ChatMessage.AuthorRoles.User, deserializedPlan.OriginalUserInput); // Add bot message proposal as prompt context message - chatContext.Variables.Set("planFunctions", this._externalInformationSkill.FormattedFunctionsString(deserializedPlan.Plan)); + chatContext.Variables.Set("planFunctions", this._externalInformationPlugin.FormattedFunctionsString(deserializedPlan.Plan)); var promptTemplateFactory = new BasicPromptTemplateFactory(); var proposedPlanTemplate = promptTemplateFactory.Create(this._promptOptions.ProposedPlanBotMessage, new PromptTemplateConfig()); var proposedPlanBotMessage = await proposedPlanTemplate.RenderAsync(chatContext, cancellationToken); @@ -480,7 +480,7 @@ await this.SaveNewResponseAsync( } else { - this._logger.LogWarning("ChatSkill.ProcessPlan token usage unknown. Ensure token management has been implemented correctly."); + this._logger.LogWarning("ChatPlugin.ProcessPlan token usage unknown. Ensure token management has been implemented correctly."); } } catch (Exception ex) @@ -555,12 +555,12 @@ private async Task GetChatResponseAsync(string chatId, string userI // Extract additional details about stepwise planner execution in chat context var plannerDetails = new SemanticDependency( - this._externalInformationSkill.StepwiseThoughtProcess?.RawResult ?? planResult, - this._externalInformationSkill.StepwiseThoughtProcess + this._externalInformationPlugin.StepwiseThoughtProcess?.RawResult ?? planResult, + this._externalInformationPlugin.StepwiseThoughtProcess ); // If plan is suggested, send back to user for approval before running - var proposedPlan = this._externalInformationSkill.ProposedPlan; + var proposedPlan = this._externalInformationPlugin.ProposedPlan; if (proposedPlan != null) { // Save a new response to the chat history with the proposed plan content @@ -576,10 +576,10 @@ private async Task GetChatResponseAsync(string chatId, string userI } // If plan result is to be used as bot response, save the Stepwise result as a new response to the chat history and return. - if (this._externalInformationSkill.UseStepwiseResultAsBotResponse(planResult)) + if (this._externalInformationPlugin.UseStepwiseResultAsBotResponse(planResult)) { var promptDetails = new BotResponsePrompt("", "", userIntent, "", plannerDetails, "", new ChatHistory()); - return await this.HandleBotResponseAsync(chatId, userId, chatContext, promptDetails, cancellationToken, null, this._externalInformationSkill.StepwiseThoughtProcess!.RawResult); + return await this.HandleBotResponseAsync(chatId, userId, chatContext, promptDetails, cancellationToken, null, this._externalInformationPlugin.StepwiseThoughtProcess!.RawResult); } // Query relevant semantic and document memories @@ -748,8 +748,8 @@ private async Task AcquireExternalInformationAsync(SKContext context, st SKContext planContext = context.Clone(); planContext.Variables.Set("tokenLimit", tokenLimit.ToString(new NumberFormatInfo())); return plan is not null - ? await this._externalInformationSkill.ExecutePlanAsync(planContext, plan, cancellationToken) - : await this._externalInformationSkill.InvokePlannerAsync(userIntent, planContext, cancellationToken); + ? await this._externalInformationPlugin.ExecutePlanAsync(planContext, plan, cancellationToken) + : await this._externalInformationPlugin.InvokePlannerAsync(userIntent, planContext, cancellationToken); } /// diff --git a/webapi/Skills/ChatSkills/CopilotChatPlanner.cs b/webapi/Plugins/Chat/CopilotChatPlanner.cs similarity index 99% rename from webapi/Skills/ChatSkills/CopilotChatPlanner.cs rename to webapi/Plugins/Chat/CopilotChatPlanner.cs index 9a6893798..f88783c3d 100644 --- a/webapi/Skills/ChatSkills/CopilotChatPlanner.cs +++ b/webapi/Plugins/Chat/CopilotChatPlanner.cs @@ -17,10 +17,10 @@ using Microsoft.SemanticKernel.Planners; using Microsoft.SemanticKernel.Planning; -namespace CopilotChat.WebApi.Skills.ChatSkills; +namespace CopilotChat.WebApi.Plugins.Chat; /// -/// A lightweight wrapper around a planner to allow for curating which skills are available to it. +/// A lightweight wrapper around a planner to allow for curating which functions are available to it. /// public class CopilotChatPlanner { diff --git a/webapi/Skills/ChatSkills/ExternalInformationSkill.cs b/webapi/Plugins/Chat/ExternalInformationPlugin.cs similarity index 86% rename from webapi/Skills/ChatSkills/ExternalInformationSkill.cs rename to webapi/Plugins/Chat/ExternalInformationPlugin.cs index e6786b3b6..bcf08c44a 100644 --- a/webapi/Skills/ChatSkills/ExternalInformationSkill.cs +++ b/webapi/Plugins/Chat/ExternalInformationPlugin.cs @@ -11,9 +11,9 @@ using System.Threading.Tasks; using CopilotChat.WebApi.Models.Response; using CopilotChat.WebApi.Options; -using CopilotChat.WebApi.Skills.OpenApiPlugins.GitHubPlugin.Model; -using CopilotChat.WebApi.Skills.OpenApiPlugins.JiraPlugin.Model; -using CopilotChat.WebApi.Skills.Utils; +using CopilotChat.WebApi.Plugins.OpenApi.GitHubPlugin.Model; +using CopilotChat.WebApi.Plugins.OpenApi.JiraPlugin.Model; +using CopilotChat.WebApi.Plugins.Utils; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; @@ -23,12 +23,12 @@ using Microsoft.SemanticKernel.TemplateEngine; using Microsoft.SemanticKernel.TemplateEngine.Basic; -namespace CopilotChat.WebApi.Skills.ChatSkills; +namespace CopilotChat.WebApi.Plugins.Chat; /// -/// This skill provides the functions to acquire external information. +/// This plugin provides the functions to acquire external information. /// -public class ExternalInformationSkill +public class ExternalInformationPlugin { /// /// High level logger. @@ -66,9 +66,9 @@ public class ExternalInformationSkill private const string ResultHeader = "RESULT: "; /// - /// Create a new instance of ExternalInformationSkill. + /// Create a new instance of ExternalInformationPlugin. /// - public ExternalInformationSkill( + public ExternalInformationPlugin( IOptions promptOptions, CopilotChatPlanner planner, ILogger logger) @@ -170,12 +170,12 @@ public async Task ExecutePlanAsync( - TokenUtils.TokenCount(functionsUsed) - TokenUtils.TokenCount(ResultHeader); - // The result of the plan may be from an OpenAPI skill. Attempt to extract JSON from the response. + // The result of the plan may be from an OpenAPI plugin. Attempt to extract JSON from the response. bool extractJsonFromOpenApi = this.TryExtractJsonFromOpenApiPlanResult(newPlanContext, newPlanContext.Result, out string planResult); if (extractJsonFromOpenApi) { - planResult = this.OptimizeOpenApiSkillJson(planResult, tokenLimit, plan); + planResult = this.OptimizeOpenApiPluginJson(planResult, tokenLimit, plan); } else { @@ -229,7 +229,7 @@ private async Task RunStepwisePlannerAsync(string goal, SKContext contex this.StepwiseThoughtProcess = new PlanExecutionMetadata( plannerContext.Variables["stepsTaken"], plannerContext.Variables["timeTaken"], - plannerContext.Variables["skillCount"], + plannerContext.Variables["pluginCount"], plannerResult); // Return empty string if result was not found so it's omitted from the meta prompt. @@ -280,13 +280,13 @@ private void MergeContextIntoPlan(ContextVariables variables, ContextVariables p } /// - /// Try to extract json from the planner response as if it were from an OpenAPI skill. + /// Try to extract json from the planner response as if it were from an OpenAPI plugin. /// - private bool TryExtractJsonFromOpenApiPlanResult(SKContext context, string openApiSkillResponse, out string json) + private bool TryExtractJsonFromOpenApiPlanResult(SKContext context, string openApiPluginResponse, out string json) { try { - JsonNode? jsonNode = JsonNode.Parse(openApiSkillResponse); + JsonNode? jsonNode = JsonNode.Parse(openApiPluginResponse); string contentType = jsonNode?["contentType"]?.ToString() ?? string.Empty; if (contentType.StartsWith("application/json", StringComparison.InvariantCultureIgnoreCase)) { @@ -300,7 +300,7 @@ private bool TryExtractJsonFromOpenApiPlanResult(SKContext context, string openA } catch (JsonException) { - this._logger.LogDebug("Unable to extract JSON from planner response, it is likely not from an OpenAPI skill."); + this._logger.LogDebug("Unable to extract JSON from planner response, it is likely not from an OpenAPI plugin."); } catch (InvalidOperationException) { @@ -316,24 +316,24 @@ private bool TryExtractJsonFromOpenApiPlanResult(SKContext context, string openA /// Try to optimize json from the planner response /// based on token limit /// - private string OptimizeOpenApiSkillJson(string jsonContent, int tokenLimit, Plan plan) + private string OptimizeOpenApiPluginJson(string jsonContent, int tokenLimit, Plan plan) { // Remove all new line characters + leading and trailing white space jsonContent = Regex.Replace(jsonContent.Trim(), @"[\n\r]", string.Empty); var document = JsonDocument.Parse(jsonContent); - string lastSkillInvoked = plan.Steps[^1].PluginName; - string lastSkillFunctionInvoked = plan.Steps[^1].Name; - bool trimSkillResponse = false; + string lastPluginInvoked = plan.Steps[^1].PluginName; + string lastFunctionInvoked = plan.Steps[^1].Name; + bool trimResponse = false; // The json will be deserialized based on the response type of the particular operation that was last invoked by the planner // The response type can be a custom trimmed down json structure, which is useful in staying within the token limit - Type skillResponseType = this.GetOpenApiSkillResponseType(ref document, ref lastSkillInvoked, ref lastSkillFunctionInvoked, ref trimSkillResponse); + Type responseType = this.GetOpenApiFunctionResponseType(ref document, ref lastPluginInvoked, ref lastFunctionInvoked, ref trimResponse); - if (trimSkillResponse) + if (trimResponse) { - // Deserializing limits the json content to only the fields defined in the respective OpenApiSkill's Model classes - var skillResponse = JsonSerializer.Deserialize(jsonContent, skillResponseType); - jsonContent = skillResponse != null ? JsonSerializer.Serialize(skillResponse) : string.Empty; + // Deserializing limits the json content to only the fields defined in the respective OpenApi's Model classes + var functionResponse = JsonSerializer.Deserialize(jsonContent, responseType); + jsonContent = functionResponse != null ? JsonSerializer.Serialize(functionResponse) : string.Empty; document = JsonDocument.Parse(jsonContent); } @@ -414,39 +414,39 @@ private string OptimizeOpenApiSkillJson(string jsonContent, int tokenLimit, Plan return itemList.Count > 0 ? string.Format(CultureInfo.InvariantCulture, "{0}{1}", resultsDescriptor, JsonSerializer.Serialize(itemList)) - : string.Format(CultureInfo.InvariantCulture, "JSON response from {0} is too large to be consumed at this time.", this._planner.PlannerOptions?.Type == PlanType.Sequential ? "plan" : lastSkillInvoked); + : string.Format(CultureInfo.InvariantCulture, "JSON response from {0} is too large to be consumed at this time.", this._planner.PlannerOptions?.Type == PlanType.Sequential ? "plan" : lastPluginInvoked); } - private Type GetOpenApiSkillResponseType(ref JsonDocument document, ref string lastSkillInvoked, ref string lastSkillFunctionInvoked, ref bool trimSkillResponse) + private Type GetOpenApiFunctionResponseType(ref JsonDocument document, ref string lastPluginInvoked, ref string lastFunctionInvoked, ref bool trimResponse) { // TODO: [Issue #93] Find a way to determine response type if multiple steps are invoked - Type skillResponseType = typeof(object); // Use a reasonable default response type + Type responseType = typeof(object); // Use a reasonable default response type - // Different operations under the skill will return responses as json structures; + // Different operations under the plugin will return responses as json structures; // Prune each operation response according to the most important/contextual fields only to avoid going over the token limit - // Check what the last skill invoked was and deserialize the JSON content accordingly - if (string.Equals(lastSkillInvoked, "GitHubPlugin", StringComparison.Ordinal)) + // Check what the last function invoked was and deserialize the JSON content accordingly + if (string.Equals(lastPluginInvoked, "GitHubPlugin", StringComparison.Ordinal)) { - trimSkillResponse = true; - skillResponseType = this.GetGithubSkillResponseType(ref document); + trimResponse = true; + responseType = this.GetGithubPluginResponseType(ref document); } - else if (string.Equals(lastSkillInvoked, "JiraPlugin", StringComparison.Ordinal)) + else if (string.Equals(lastPluginInvoked, "JiraPlugin", StringComparison.Ordinal)) { - trimSkillResponse = true; - skillResponseType = this.GetJiraPluginResponseType(ref document, ref lastSkillFunctionInvoked); + trimResponse = true; + responseType = this.GetJiraPluginResponseType(ref document, ref lastFunctionInvoked); } - return skillResponseType; + return responseType; } - private Type GetGithubSkillResponseType(ref JsonDocument document) + private Type GetGithubPluginResponseType(ref JsonDocument document) { return document.RootElement.ValueKind == JsonValueKind.Array ? typeof(PullRequest[]) : typeof(PullRequest); } - private Type GetJiraPluginResponseType(ref JsonDocument document, ref string lastSkillFunctionInvoked) + private Type GetJiraPluginResponseType(ref JsonDocument document, ref string lastFunctionInvoked) { - if (lastSkillFunctionInvoked == "GetIssue") + if (lastFunctionInvoked == "GetIssue") { return document.RootElement.ValueKind == JsonValueKind.Array ? typeof(IssueResponse[]) : typeof(IssueResponse); } @@ -471,7 +471,7 @@ private List GetPlanSteps(Plan plan) } /// - /// Returns a string representation of the chat context, excluding some variables that are only relevant to the ChatSkill execution context and should be ignored by the planner. + /// Returns a string representation of the chat context, excluding some variables that are only relevant to the ChatPlugin execution context and should be ignored by the planner. /// This helps clarify the context that is passed to the planner as well as save on tokens. /// /// The chat context object that contains the variables and their values. diff --git a/webapi/Skills/ChatSkills/SemanticChatMemory.cs b/webapi/Plugins/Chat/SemanticChatMemory.cs similarity index 96% rename from webapi/Skills/ChatSkills/SemanticChatMemory.cs rename to webapi/Plugins/Chat/SemanticChatMemory.cs index 4aa82d726..e01684553 100644 --- a/webapi/Skills/ChatSkills/SemanticChatMemory.cs +++ b/webapi/Plugins/Chat/SemanticChatMemory.cs @@ -5,7 +5,7 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace CopilotChat.WebApi.Skills.ChatSkills; +namespace CopilotChat.WebApi.Plugins.Chat; /// /// A collection of semantic chat memory. diff --git a/webapi/Skills/ChatSkills/SemanticChatMemoryExtractor.cs b/webapi/Plugins/Chat/SemanticChatMemoryExtractor.cs similarity index 98% rename from webapi/Skills/ChatSkills/SemanticChatMemoryExtractor.cs rename to webapi/Plugins/Chat/SemanticChatMemoryExtractor.cs index 0761fabb2..aa99844fe 100644 --- a/webapi/Skills/ChatSkills/SemanticChatMemoryExtractor.cs +++ b/webapi/Plugins/Chat/SemanticChatMemoryExtractor.cs @@ -7,14 +7,14 @@ using CopilotChat.WebApi.Extensions; using CopilotChat.WebApi.Models.Request; using CopilotChat.WebApi.Options; -using CopilotChat.WebApi.Skills.Utils; +using CopilotChat.WebApi.Plugins.Utils; using Microsoft.Extensions.Logging; using Microsoft.KernelMemory; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.Connectors.AI.OpenAI; using Microsoft.SemanticKernel.Orchestration; -namespace CopilotChat.WebApi.Skills.ChatSkills; +namespace CopilotChat.WebApi.Plugins.Chat; /// /// Helper class to extract and create kernel memory from chat history. diff --git a/webapi/Skills/ChatSkills/SemanticChatMemoryItem.cs b/webapi/Plugins/Chat/SemanticChatMemoryItem.cs similarity index 95% rename from webapi/Skills/ChatSkills/SemanticChatMemoryItem.cs rename to webapi/Plugins/Chat/SemanticChatMemoryItem.cs index 5012290ba..67697c9dd 100644 --- a/webapi/Skills/ChatSkills/SemanticChatMemoryItem.cs +++ b/webapi/Plugins/Chat/SemanticChatMemoryItem.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; -namespace CopilotChat.WebApi.Skills.ChatSkills; +namespace CopilotChat.WebApi.Plugins.Chat; /// /// A single entry in the chat memory. diff --git a/webapi/Skills/ChatSkills/SemanticMemoryRetriever.cs b/webapi/Plugins/Chat/SemanticMemoryRetriever.cs similarity index 99% rename from webapi/Skills/ChatSkills/SemanticMemoryRetriever.cs rename to webapi/Plugins/Chat/SemanticMemoryRetriever.cs index c14f3c832..fca472e7c 100644 --- a/webapi/Skills/ChatSkills/SemanticMemoryRetriever.cs +++ b/webapi/Plugins/Chat/SemanticMemoryRetriever.cs @@ -9,13 +9,13 @@ using CopilotChat.WebApi.Extensions; using CopilotChat.WebApi.Models.Storage; using CopilotChat.WebApi.Options; -using CopilotChat.WebApi.Skills.Utils; +using CopilotChat.WebApi.Plugins.Utils; using CopilotChat.WebApi.Storage; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.KernelMemory; -namespace CopilotChat.WebApi.Skills.ChatSkills; +namespace CopilotChat.WebApi.Plugins.Chat; /// /// This class provides the functions to query kernel memory. diff --git a/webapi/Skills/OpenApiPlugins/GitHubPlugin/Model/Label.cs b/webapi/Plugins/OpenApi/GitHubPlugin/Model/Label.cs similarity index 93% rename from webapi/Skills/OpenApiPlugins/GitHubPlugin/Model/Label.cs rename to webapi/Plugins/OpenApi/GitHubPlugin/Model/Label.cs index 48b1f3957..bc3234a9e 100644 --- a/webapi/Skills/OpenApiPlugins/GitHubPlugin/Model/Label.cs +++ b/webapi/Plugins/OpenApi/GitHubPlugin/Model/Label.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; -namespace CopilotChat.WebApi.Skills.OpenApiPlugins.GitHubPlugin.Model; +namespace CopilotChat.WebApi.Plugins.OpenApi.GitHubPlugin.Model; /// /// Represents a pull request label. diff --git a/webapi/Skills/OpenApiPlugins/GitHubPlugin/Model/PullRequest.cs b/webapi/Plugins/OpenApi/GitHubPlugin/Model/PullRequest.cs similarity index 98% rename from webapi/Skills/OpenApiPlugins/GitHubPlugin/Model/PullRequest.cs rename to webapi/Plugins/OpenApi/GitHubPlugin/Model/PullRequest.cs index 1d5ecaab5..d5d9ad266 100644 --- a/webapi/Skills/OpenApiPlugins/GitHubPlugin/Model/PullRequest.cs +++ b/webapi/Plugins/OpenApi/GitHubPlugin/Model/PullRequest.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Text.Json.Serialization; -namespace CopilotChat.WebApi.Skills.OpenApiPlugins.GitHubPlugin.Model; +namespace CopilotChat.WebApi.Plugins.OpenApi.GitHubPlugin.Model; /// /// Represents a GitHub Pull Request. diff --git a/webapi/Skills/OpenApiPlugins/GitHubPlugin/Model/Repo.cs b/webapi/Plugins/OpenApi/GitHubPlugin/Model/Repo.cs similarity index 92% rename from webapi/Skills/OpenApiPlugins/GitHubPlugin/Model/Repo.cs rename to webapi/Plugins/OpenApi/GitHubPlugin/Model/Repo.cs index 4ccb6828b..72c1f2501 100644 --- a/webapi/Skills/OpenApiPlugins/GitHubPlugin/Model/Repo.cs +++ b/webapi/Plugins/OpenApi/GitHubPlugin/Model/Repo.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; -namespace CopilotChat.WebApi.Skills.OpenApiPlugins.GitHubPlugin.Model; +namespace CopilotChat.WebApi.Plugins.OpenApi.GitHubPlugin.Model; /// /// Represents a GitHub Repo. diff --git a/webapi/Skills/OpenApiPlugins/GitHubPlugin/Model/User.cs b/webapi/Plugins/OpenApi/GitHubPlugin/Model/User.cs similarity index 95% rename from webapi/Skills/OpenApiPlugins/GitHubPlugin/Model/User.cs rename to webapi/Plugins/OpenApi/GitHubPlugin/Model/User.cs index 61941f891..3e04ec106 100644 --- a/webapi/Skills/OpenApiPlugins/GitHubPlugin/Model/User.cs +++ b/webapi/Plugins/OpenApi/GitHubPlugin/Model/User.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; -namespace CopilotChat.WebApi.Skills.OpenApiPlugins.GitHubPlugin.Model; +namespace CopilotChat.WebApi.Plugins.OpenApi.GitHubPlugin.Model; /// /// Represents a user on GitHub. diff --git a/webapi/Skills/OpenApiPlugins/GitHubPlugin/openapi.json b/webapi/Plugins/OpenApi/GitHubPlugin/openapi.json similarity index 100% rename from webapi/Skills/OpenApiPlugins/GitHubPlugin/openapi.json rename to webapi/Plugins/OpenApi/GitHubPlugin/openapi.json diff --git a/webapi/Skills/OpenApiPlugins/JiraPlugin/Model/CommentAuthor.cs b/webapi/Plugins/OpenApi/JiraPlugin/Model/CommentAuthor.cs similarity index 90% rename from webapi/Skills/OpenApiPlugins/JiraPlugin/Model/CommentAuthor.cs rename to webapi/Plugins/OpenApi/JiraPlugin/Model/CommentAuthor.cs index 429f414e4..268f02743 100644 --- a/webapi/Skills/OpenApiPlugins/JiraPlugin/Model/CommentAuthor.cs +++ b/webapi/Plugins/OpenApi/JiraPlugin/Model/CommentAuthor.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; -namespace CopilotChat.WebApi.Skills.OpenApiPlugins.JiraPlugin.Model; +namespace CopilotChat.WebApi.Plugins.OpenApi.JiraPlugin.Model; /// /// Represents the Author of a comment. diff --git a/webapi/Skills/OpenApiPlugins/JiraPlugin/Model/CommentResponse.cs b/webapi/Plugins/OpenApi/JiraPlugin/Model/CommentResponse.cs similarity index 92% rename from webapi/Skills/OpenApiPlugins/JiraPlugin/Model/CommentResponse.cs rename to webapi/Plugins/OpenApi/JiraPlugin/Model/CommentResponse.cs index f8b18b1bc..1058046de 100644 --- a/webapi/Skills/OpenApiPlugins/JiraPlugin/Model/CommentResponse.cs +++ b/webapi/Plugins/OpenApi/JiraPlugin/Model/CommentResponse.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text.Json.Serialization; -namespace CopilotChat.WebApi.Skills.OpenApiPlugins.JiraPlugin.Model; +namespace CopilotChat.WebApi.Plugins.OpenApi.JiraPlugin.Model; /// /// Represents a the list of comments that make up a CommentResponse. diff --git a/webapi/Skills/OpenApiPlugins/JiraPlugin/Model/IndividualComments.cs b/webapi/Plugins/OpenApi/JiraPlugin/Model/IndividualComments.cs similarity index 92% rename from webapi/Skills/OpenApiPlugins/JiraPlugin/Model/IndividualComments.cs rename to webapi/Plugins/OpenApi/JiraPlugin/Model/IndividualComments.cs index d8f191136..420f52f7d 100644 --- a/webapi/Skills/OpenApiPlugins/JiraPlugin/Model/IndividualComments.cs +++ b/webapi/Plugins/OpenApi/JiraPlugin/Model/IndividualComments.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; -namespace CopilotChat.WebApi.Skills.OpenApiPlugins.JiraPlugin.Model; +namespace CopilotChat.WebApi.Plugins.OpenApi.JiraPlugin.Model; /// /// Represents an individual comment on an issue in jira. diff --git a/webapi/Skills/OpenApiPlugins/JiraPlugin/Model/IssueResponse.cs b/webapi/Plugins/OpenApi/JiraPlugin/Model/IssueResponse.cs similarity index 95% rename from webapi/Skills/OpenApiPlugins/JiraPlugin/Model/IssueResponse.cs rename to webapi/Plugins/OpenApi/JiraPlugin/Model/IssueResponse.cs index 2b32e6ac1..1790264a1 100644 --- a/webapi/Skills/OpenApiPlugins/JiraPlugin/Model/IssueResponse.cs +++ b/webapi/Plugins/OpenApi/JiraPlugin/Model/IssueResponse.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; -namespace CopilotChat.WebApi.Skills.OpenApiPlugins.JiraPlugin.Model; +namespace CopilotChat.WebApi.Plugins.OpenApi.JiraPlugin.Model; /// /// Represents a the trimmed down response for retrieving an issue from jira. diff --git a/webapi/Skills/OpenApiPlugins/JiraPlugin/Model/IssueResponseFIeld.cs b/webapi/Plugins/OpenApi/JiraPlugin/Model/IssueResponseFIeld.cs similarity index 95% rename from webapi/Skills/OpenApiPlugins/JiraPlugin/Model/IssueResponseFIeld.cs rename to webapi/Plugins/OpenApi/JiraPlugin/Model/IssueResponseFIeld.cs index 9a949da69..92902930c 100644 --- a/webapi/Skills/OpenApiPlugins/JiraPlugin/Model/IssueResponseFIeld.cs +++ b/webapi/Plugins/OpenApi/JiraPlugin/Model/IssueResponseFIeld.cs @@ -2,7 +2,7 @@ using System.Text.Json.Serialization; -namespace CopilotChat.WebApi.Skills.OpenApiPlugins.JiraPlugin.Model; +namespace CopilotChat.WebApi.Plugins.OpenApi.JiraPlugin.Model; /// /// Represents the fields that make up an IssueResponse. diff --git a/webapi/Skills/OpenApiPlugins/JiraPlugin/openapi.json b/webapi/Plugins/OpenApi/JiraPlugin/openapi.json similarity index 100% rename from webapi/Skills/OpenApiPlugins/JiraPlugin/openapi.json rename to webapi/Plugins/OpenApi/JiraPlugin/openapi.json diff --git a/webapi/Skills/OpenApiPlugins/README.md b/webapi/Plugins/OpenApi/README.md similarity index 69% rename from webapi/Skills/OpenApiPlugins/README.md rename to webapi/Plugins/OpenApi/README.md index 442c18fec..c6f2aa33e 100644 --- a/webapi/Skills/OpenApiPlugins/README.md +++ b/webapi/Plugins/OpenApi/README.md @@ -1,4 +1,4 @@ -# OpenAPI Skills +# OpenAPI Plugins ## GitHubPlugin @@ -19,5 +19,5 @@ Version 3.0 of jira's swagger document is hosted at https://developer.atlassian. # Model Classes -OpenApi skills return responses as json structures, these responses can vary based on the functions that are eventually invoked. Some responses are very big and go over the token limit of the underlying language model. To work around the token limit we can specifically prune the json response before passing that information back to the language model. -The Model classes under `.\webapi\Skills\OpenApiSkills\\Model\` determine which json properties are picked for deserializing the json response; Only the json properties defined via the Model classes remain in the trimmed response passed back to the language model. +OpenApi plugins return responses as json structures, these responses can vary based on the functions that are eventually invoked. Some responses are very big and go over the token limit of the underlying language model. To work around the token limit we can specifically prune the json response before passing that information back to the language model. +The Model classes under `.\webapi\Plugins\OpenApiS\\Model\` determine which json properties are picked for deserializing the json response; Only the json properties defined via the Model classes remain in the trimmed response passed back to the language model. diff --git a/webapi/Skills/Utils/AsyncUtils.cs b/webapi/Plugins/Utils/AsyncUtils.cs similarity index 97% rename from webapi/Skills/Utils/AsyncUtils.cs rename to webapi/Plugins/Utils/AsyncUtils.cs index 5a7f367a6..7b71e24f0 100644 --- a/webapi/Skills/Utils/AsyncUtils.cs +++ b/webapi/Plugins/Utils/AsyncUtils.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; using Microsoft.SemanticKernel.Diagnostics; -namespace CopilotChat.WebApi.Skills.Utils; +namespace CopilotChat.WebApi.Plugins.Utils; /// /// Utility methods for working with asynchronous operations and callbacks. diff --git a/webapi/Skills/Utils/PromptUtils.cs b/webapi/Plugins/Utils/PromptUtils.cs similarity index 93% rename from webapi/Skills/Utils/PromptUtils.cs rename to webapi/Plugins/Utils/PromptUtils.cs index f9794f25c..8969266e6 100644 --- a/webapi/Skills/Utils/PromptUtils.cs +++ b/webapi/Plugins/Utils/PromptUtils.cs @@ -2,7 +2,7 @@ using static CopilotChat.WebApi.Models.Storage.ChatMessage; -namespace CopilotChat.WebApi.Skills.Utils; +namespace CopilotChat.WebApi.Plugins.Utils; /// /// Utility methods for prompt generation. diff --git a/webapi/Skills/Utils/TokenUtils.cs b/webapi/Plugins/Utils/TokenUtils.cs similarity index 98% rename from webapi/Skills/Utils/TokenUtils.cs rename to webapi/Plugins/Utils/TokenUtils.cs index f3c091ab1..ee9086c9f 100644 --- a/webapi/Skills/Utils/TokenUtils.cs +++ b/webapi/Plugins/Utils/TokenUtils.cs @@ -12,7 +12,7 @@ using Microsoft.SemanticKernel.Orchestration; using ChatCompletionContextMessages = Microsoft.SemanticKernel.AI.ChatCompletion.ChatHistory; -namespace CopilotChat.WebApi.Skills.Utils; +namespace CopilotChat.WebApi.Plugins.Utils; /// /// Utility methods for token management. @@ -22,7 +22,7 @@ public static class TokenUtils private static SharpToken.GptEncoding tokenizer = SharpToken.GptEncoding.GetEncoding("cl100k_base"); /// - /// Semantic dependencies of ChatSkill. + /// Semantic dependencies of ChatPlugin. /// If you add a new semantic dependency, please add it here. /// public static readonly Dictionary semanticFunctions = new() diff --git a/webapi/README.md b/webapi/README.md index 4df7a7634..4996aea7b 100644 --- a/webapi/README.md +++ b/webapi/README.md @@ -90,7 +90,7 @@ To enable sequential planner, 1. In [./webapi/appsettings.json](appsettings.json), set `"Type": "Sequential"` under the `Planner` section. 1. Then, set your preferred Planner model (`gpt-4` or `gpt-3.5-turbo`) under the `AIService` configuration section. 1. If using `gpt-4`, no other changes are required. -1. If using `gpt-3.5-turbo`: change [CopilotChatPlanner.cs](Skills/ChatSkills/CopilotChatPlanner.cs) to initialize SequentialPlanner with a RelevancyThreshold\*. +1. If using `gpt-3.5-turbo`: change [CopilotChatPlanner.cs](Plugins/Chat/CopilotChatPlanner.cs) to initialize SequentialPlanner with a RelevancyThreshold\*. - Add `using` statement to top of file: ``` using Microsoft.SemanticKernel.Planning.Sequential; @@ -164,7 +164,7 @@ To use Application Insights, first create an instance in your Azure subscription On the resource overview page, in the top right use the copy button to copy the Connection String and paste this into the `APPLICATIONINSIGHTS_CONNECTION_STRING` setting as either a appsettings value, or add it as a secret. -In addition to this there are some custom events that can inform you how users are using the service such as `SkillFunction`. +In addition to this there are some custom events that can inform you how users are using the service such as `PluginFunction`. To access these custom events the suggested method is to use Azure Data Explorer (ADX). To access data from Application Insights in ADX, create a new dashboard and add a new Data Source (use the ellipsis dropdown in the top right). @@ -174,24 +174,24 @@ For more info see [Query data in Azure Monitor using Azure Data Explorer](https: CopilotChat specific events are in a table called `customEvents`. -For example to see the most recent 100 skill function invocations: +For example to see the most recent 100 plugin function invocations: ```kql customEvents | where timestamp between (_startTime .. _endTime) -| where name == "SkillFunction" -| extend skill = tostring(customDimensions.skillName) +| where name == "PluginFunction" +| extend plugin = tostring(customDimensions.pluginName) | extend function = tostring(customDimensions.functionName) | extend success = tobool(customDimensions.success) | extend userId = tostring(customDimensions.userId) | extend environment = tostring(customDimensions.AspNetCoreEnvironment) -| extend skillFunction = strcat(skill, '/', function) -| project timestamp, skillFunction, success, userId, environment +| extend pluginFunction = strcat(plugin, '/', function) +| project timestamp, pluginFunction, success, userId, environment | order by timestamp desc | limit 100 ``` -Or to report the success rate of skill functions against environments, you can first add a parameter to the dashboard to filter the environment. +Or to report the success rate of plugin functions against environments, you can first add a parameter to the dashboard to filter the environment. You can use this query to show the environments available by adding the `Source` as this `Query`: @@ -209,14 +209,14 @@ You can then query the success rate with this query: ```kql customEvents | where timestamp between (_startTime .. _endTime) -| where name == "SkillFunction" -| extend skill = tostring(customDimensions.skillName) +| where name == "PluginFunction" +| extend plugin = tostring(customDimensions.pluginName) | extend function = tostring(customDimensions.functionName) | extend success = tobool(customDimensions.success) | extend environment = tostring(customDimensions.AspNetCoreEnvironment) -| extend skillFunction = strcat(skill, '/', function) -| summarize Total=count(), Success=countif(success) by skillFunction, environment -| project skillFunction, SuccessPercentage = 100.0 * Success/Total, environment +| extend pluginFunction = strcat(plugin, '/', function) +| summarize Total=count(), Success=countif(success) by pluginFunction, environment +| project pluginFunction, SuccessPercentage = 100.0 * Success/Total, environment | order by SuccessPercentage asc ``` @@ -227,14 +227,14 @@ Finally you could render this data over time with a query like this: ```kql customEvents | where timestamp between (_startTime .. _endTime) -| where name == "SkillFunction" -| extend skill = tostring(customDimensions.skillName) +| where name == "PluginFunction" +| extend plugin = tostring(customDimensions.pluginName) | extend function = tostring(customDimensions.functionName) | extend success = tobool(customDimensions.success) | extend environment = tostring(customDimensions.AspNetCoreEnvironment) -| extend skillFunction = strcat(skill, '/', function) -| summarize Total=count(), Success=countif(success) by skillFunction, environment, bin(timestamp,1m) -| project skillFunction, SuccessPercentage = 100.0 * Success/Total, environment, timestamp +| extend pluginFunction = strcat(plugin, '/', function) +| summarize Total=count(), Success=countif(success) by pluginFunction, environment, bin(timestamp,1m) +| project pluginFunction, SuccessPercentage = 100.0 * Success/Total, environment, timestamp | order by timestamp asc ``` @@ -248,14 +248,14 @@ Then use a Time chart on the Visual tab. If you wish to load custom plugins into the kernel or planner: -1. Create two new folders under `./Skills` directory named `./SemanticPlugins` and `./NativePlugins`. There, you can add your custom plugins (synonymous with skills). +1. Create two new folders under `./Plugins` directory named `./SemanticPlugins` and `./NativePlugins`. There, you can add your custom plugins (synonymous with plugins). 2. Then, comment out the respective options in `appsettings.json`: ```json "Service": { // "TimeoutLimitInS": "120" - "SemanticPluginsDirectory": "./Skills/SemanticPlugins", - "NativePluginsDirectory": "./Skills/NativePlugins" + "SemanticPluginsDirectory": "./Plugins/SemanticPlugins", + "NativePluginsDirectory": "./Plugins/NativePlugins" // "KeyVault": "" // "InMaintenance": true }, @@ -280,9 +280,9 @@ If you wish to load custom plugins into the kernel or planner: If you want to deploy your custom plugins with the webapi, additional configuration is required. You have the following options: -1. **[Recommended]** Create custom setup hooks to import your skills into the kernel and planner. +1. **[Recommended]** Create custom setup hooks to import your plugins into the kernel and planner. - > The default `RegisterSkillsAsync` function uses reflection to import native functions from your custom plugin files. C# reflection is a powerful but slow mechanism that dynamically inspects and invokes types and methods at runtime. It works well for loading a few plugin files, but it can degrade performance and increase memory usage if you have many plugins or complex types. Therefore, we recommend creating your own import function to load your custom plugins manually. This way, you can avoid reflection overhead and have more control over how and when your plugins are loaded. + > The default `RegisterPluginsAsync` function uses reflection to import native functions from your custom plugin files. C# reflection is a powerful but slow mechanism that dynamically inspects and invokes types and methods at runtime. It works well for loading a few plugin files, but it can degrade performance and increase memory usage if you have many plugins or complex types. Therefore, we recommend creating your own import function to load your custom plugins manually. This way, you can avoid reflection overhead and have more control over how and when your plugins are loaded. Create a function to load your custom plugins at build and pass that function as a hook to `AddKernelSetupHook` or `AddPlannerSetupHook` in `SemanticKernelExtensions.cs`. See the [next two sections](#add-custom-setup-to-chat-copilots-kernel) for details on how to do this. This bypasses the need to load the plugins at runtime, and consequently, there's no need to ship the source files for your custom plugins. Remember to comment out the `NativePluginsDirectory` or `SemanticPluginsDirectory` options in `appsettings.json` to prevent any potential pathing errors. @@ -290,13 +290,13 @@ Alternatively, 2. If you want to use local files for custom plugins and don't mind exposing your source code, you need to make sure that the files are copied to the output directory when you publish or run the app. The deployed app expects to find the files in a subdirectory specified by the `NativePluginsDirectory` or `SemanticPluginsDirectory` option, which is relative to the assembly location by default. To copy the files to the output directory, - Mark the files and the subdirectory as Copy to Output Directory in the project file or the file properties. For example, if your files are in a subdirectories called `Skills\NativePlugins` and `Skills\SemanticPlugins`, you can uncomment the following lines the `CopilotChatWebApi.csproj` file: + Mark the files and the subdirectory as Copy to Output Directory in the project file or the file properties. For example, if your files are in a subdirectories called `Plugins\NativePlugins` and `Plugins\SemanticPlugins`, you can uncomment the following lines the `CopilotChatWebApi.csproj` file: ```xml - + PreserveNewest - + PreserveNewest ``` @@ -315,7 +315,7 @@ For example, the following code snippet shows how to create a custom hook that r private static Task MyCustomSetupHook(IServiceProvider sp, IKernel kernel) { // Import your plugin into the kernel with the name "MyPlugin" - kernel.ImportSkill(new MyPlugin(), nameof(MyPlugin)); + kernel.ImportFunctions(new MyPlugin(), nameof(MyPlugin)); // Perform any other setup actions on the kernel // ... diff --git a/webapi/Services/AppInsightsTelemetryService.cs b/webapi/Services/AppInsightsTelemetryService.cs index b424b8c1b..9f38d2a41 100644 --- a/webapi/Services/AppInsightsTelemetryService.cs +++ b/webapi/Services/AppInsightsTelemetryService.cs @@ -30,16 +30,16 @@ public AppInsightsTelemetryService(TelemetryClient telemetryClient, IHttpContext } /// - public void TrackSkillFunction(string skillName, string functionName, bool success) + public void TrackPluginFunction(string pluginName, string functionName, bool success) { var properties = new Dictionary(this.BuildDefaultProperties()) { - { "skillName", skillName }, + { "pluginName", pluginName }, { "functionName", functionName }, { "success", success.ToString() }, }; - this._telemetryClient.TrackEvent("SkillFunction", properties); + this._telemetryClient.TrackEvent("PluginFunction", properties); } /// diff --git a/webapi/Services/ITelemetryService.cs b/webapi/Services/ITelemetryService.cs index 46c65a8e2..9c222e4d7 100644 --- a/webapi/Services/ITelemetryService.cs +++ b/webapi/Services/ITelemetryService.cs @@ -8,10 +8,10 @@ namespace CopilotChat.WebApi.Services; public interface ITelemetryService { /// - /// Creates a telemetry event when a skill function is executed. + /// Creates a telemetry event when a function is executed. /// - /// Name of the skill - /// Skill function name - /// If the skill executed successfully - void TrackSkillFunction(string skillName, string functionName, bool success); + /// Name of the plugin + /// Function name + /// If the function executed successfully + void TrackPluginFunction(string pluginName, string functionName, bool success); } diff --git a/webapi/appsettings.json b/webapi/appsettings.json index fdbc8faeb..3f0a8d615 100644 --- a/webapi/appsettings.json +++ b/webapi/appsettings.json @@ -14,16 +14,16 @@ // Service configuration // - Optionally set TimeoutLimitInS to the maximum number of seconds to wait for a response from the AI service. If this is not set, there is no timeout. // - Optionally set: - // - SemanticPluginsDirectory to the directory from which to load semantic plugins (e.g., "./Skills/SemanticPlugins"). - // - NativePluginsDirectory to the directory from which to load native plugins (e.g., "./Skills/NativePlugins"). + // - SemanticPluginsDirectory to the directory from which to load semantic plugins (e.g., "./Plugins/SemanticPlugins"). + // - NativePluginsDirectory to the directory from which to load native plugins (e.g., "./Plugins/NativePlugins"). // - Note: See webapi/README.md#Adding Custom Plugins for more details, including additional configuration required for deployment. // - Optionally set KeyVaultUri to the URI of the Key Vault for secrets (e.g., "https://contoso.vault.azure.net/"). // - Optionally set InMaintenance to true to set the application to maintenance mode. // "Service": { // "TimeoutLimitInS": "120" - // "SemanticPluginsDirectory": "./Skills/SemanticPlugins", - // "NativePluginsDirectory": "./Skills/NativePlugins" + // "SemanticPluginsDirectory": "./Plugins/SemanticPlugins", + // "NativePluginsDirectory": "./Plugins/NativePlugins" // "KeyVault": "" // "InMaintenance": true }, @@ -42,7 +42,7 @@ } }, // - // Planner can determine which skill functions, if any, need to be used to fulfill a user's request. + // Planner can determine which plugin functions, if any, need to be used to fulfill a user's request. // https://learn.microsoft.com/en-us/semantic-kernel/concepts-sk/planner // - Set Planner:Type to "Action" to use the single-step ActionPlanner // - Set Planner:Type to "Sequential" to enable the multi-step SequentialPlanner @@ -157,7 +157,7 @@ //"Key": "" }, // - // ChatSkill prompts are used to generate responses to user messages. + // ChatPlugin prompts are used to generate responses to user messages. // - CompletionTokenLimit is the token limit of the chat model, see https://platform.openai.com/docs/models/overview // and adjust the limit according to the completion model you select. // - ResponseTokenLimit is the token count left for the model to generate text after the prompt. diff --git a/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseThoughtProcessView.tsx b/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseThoughtProcessView.tsx index e6de489c1..6d31ed62b 100644 --- a/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseThoughtProcessView.tsx +++ b/webapp/src/components/chat/prompt-dialog/stepwise-planner/StepwiseThoughtProcessView.tsx @@ -65,7 +65,9 @@ export const StepwiseThoughtProcessView: React.FCTime Taken: {stepwiseDetails.timeTaken} Plugins Used: - {!stepwiseDetails.skillsUsed.startsWith('0') ? stepwiseDetails.skillsUsed : 'None'} + + {!stepwiseDetails.functionsUsed.startsWith('0') ? stepwiseDetails.functionsUsed : 'None'} + )} {(resultNotFound || showthoughtProcess) && ( diff --git a/webapp/src/components/open-api-plugins/PluginConnector.tsx b/webapp/src/components/open-api-plugins/PluginConnector.tsx index 496c7b5cb..a2ea23b51 100644 --- a/webapp/src/components/open-api-plugins/PluginConnector.tsx +++ b/webapp/src/components/open-api-plugins/PluginConnector.tsx @@ -177,7 +177,7 @@ export const PluginConnector: React.FC = ({ }, initials: '', // Set to empty string so no initials are rendered behind image }} - secondaryText={`${publisher} | Semantic Kernel Skills`} + secondaryText={`${publisher} | Semantic Kernel`} /> diff --git a/webapp/src/libs/models/PlanExecutionMetadata.ts b/webapp/src/libs/models/PlanExecutionMetadata.ts index 4312f8436..07928c587 100644 --- a/webapp/src/libs/models/PlanExecutionMetadata.ts +++ b/webapp/src/libs/models/PlanExecutionMetadata.ts @@ -8,8 +8,8 @@ export interface PlanExecutionMetadata { // Time taken to fulfil the goal. timeTaken: string; - // Skills used execution stat. - skillsUsed: string; + // Functions used execution stat. + functionsUsed: string; // Planner type. plannerType: PlanType; diff --git a/webapp/src/libs/services/ChatService.ts b/webapp/src/libs/services/ChatService.ts index a04acffa0..99beb5520 100644 --- a/webapp/src/libs/services/ChatService.ts +++ b/webapp/src/libs/services/ChatService.ts @@ -117,9 +117,9 @@ export class ChatService extends BaseService { enabledPlugins?: Plugin[], processPlan = false, ): Promise => { - // If skill requires any additional api properties, append to context + // If function requires any additional api properties, append to context if (enabledPlugins && enabledPlugins.length > 0) { - const openApiSkillVariables: IAskVariables[] = []; + const openApiVariables: IAskVariables[] = []; // List of custom plugins to append to context variables const customPlugins: ICustomPlugin[] = []; @@ -136,7 +136,7 @@ export class ChatService extends BaseService { }); } - // If skill requires any additional api properties, append to context variables + // If functions requires any additional api properties, append to context variables if (plugin.apiProperties) { const apiProperties = plugin.apiProperties; @@ -144,11 +144,11 @@ export class ChatService extends BaseService { const propertyDetails = apiProperties[property]; if (propertyDetails.required && !propertyDetails.value) { - throw new Error(`Missing required property ${property} for ${plugin.name} skill.`); + throw new Error(`Missing required property ${property} for ${plugin.name} plugin.`); } if (propertyDetails.value) { - openApiSkillVariables.push({ + openApiVariables.push({ key: `${property}`, value: propertyDetails.value, }); @@ -158,13 +158,13 @@ export class ChatService extends BaseService { } if (customPlugins.length > 0) { - openApiSkillVariables.push({ + openApiVariables.push({ key: `customPlugins`, value: JSON.stringify(customPlugins), }); } - ask.variables = ask.variables ? ask.variables.concat(openApiSkillVariables) : openApiSkillVariables; + ask.variables = ask.variables ? ask.variables.concat(openApiVariables) : openApiVariables; } const chatId = ask.variables?.find((variable) => variable.key === 'chatId')?.value as string; diff --git a/webapp/src/redux/features/plugins/PluginsState.ts b/webapp/src/redux/features/plugins/PluginsState.ts index 44b2a9ebd..50d104436 100644 --- a/webapp/src/redux/features/plugins/PluginsState.ts +++ b/webapp/src/redux/features/plugins/PluginsState.ts @@ -32,7 +32,7 @@ export interface PluginAuthRequirements { helpLink?: string; } -// Additional information required to enable OpenAPI skills, i.e., server-url +// Additional information required to enable OpenAPI functions, i.e., server-url // Key should be the property name and in kebab case (valid format for request header), // make sure it matches exactly with the property name the API requires export type AdditionalApiProperties = Record< diff --git a/webapp/tests/testsBasic.ts b/webapp/tests/testsBasic.ts index 11177749a..6bd907149 100644 --- a/webapp/tests/testsBasic.ts +++ b/webapp/tests/testsBasic.ts @@ -19,7 +19,7 @@ Summary: Tests for the following behaviour from the WebApp: - Start New Chat - Send a message to the bot, and expect a response - Chat History has the correct number of messages and that the last message is from Copilot -- SK core skill testing for jokes and fun facts +- SK core function testing for jokes and fun facts */ export async function basicBotResponses(page) { await util.loginAndCreateNewChat(page);