Skip to content

Commit

Permalink
fix all errors except for Plan type not found
Browse files Browse the repository at this point in the history
  • Loading branch information
dehoward committed Dec 17, 2023
1 parent c1758ee commit fbaae8c
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 76 deletions.
12 changes: 6 additions & 6 deletions webapi/CopilotChatWebApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<RunAnalyzersDuringBuild>true</RunAnalyzersDuringBuild>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<AnalysisLevel>latest</AnalysisLevel>
<NoWarn>SKEXP0052, SKEXP0003</NoWarn>
<NoWarn>SKEXP0011, SKEXP0021, SKEXP0026, SKEXP0042, SKEXP0052, SKEXP0053, SKEXP0003</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand All @@ -25,15 +25,15 @@
<PackageReference Include="Microsoft.KernelMemory.Core" Version="0.22.231215.2" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.0.0-rc4" />
<PackageReference Include="Microsoft.SemanticKernel.Abstractions" Version="1.0.0-rc4" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.AI.OpenAI" Version="1.0.0-rc3" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Memory.AzureCognitiveSearch" Version="1.0.0-rc2" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Memory.Qdrant" Version="1.0.0-rc3" />
<PackageReference Include="Microsoft.SemanticKernel.Functions.OpenAPI" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.OpenAI" Version="1.0.0-rc4" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.AzureAISearch" Version="1.0.0-rc4" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Qdrant" Version="1.0.0-rc4" />
<PackageReference Include="Microsoft.SemanticKernel.Planners.Core" Version="1.0.0-beta8" />
<PackageReference Include="Microsoft.SemanticKernel.Planners.OpenAI" Version="1.0.0-rc4" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Core" Version="1.0.0-rc4" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.OpenApi" Version="1.0.0-rc4" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.MsGraph" Version="1.0.0-rc4" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Web" Version="1.0.0-rc4" />
<PackageReference Include="Microsoft.SemanticKernel.TemplateEngine.Basic" Version="1.0.0-beta8" />
<PackageReference Include="SharpToken" Version="1.2.12" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion webapi/Models/Response/AskResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ public class AskResult
{
public string Value { get; set; } = string.Empty;

public IEnumerable<KeyValuePair<string, string>>? Variables { get; set; } = Enumerable.Empty<KeyValuePair<string, string>>();
public IEnumerable<KeyValuePair<string, object?>>? Variables { get; set; } = Enumerable.Empty<KeyValuePair<string, object?>>();
}
1 change: 1 addition & 0 deletions webapi/Models/Response/ProposedPlan.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System.Text.Json.Serialization;
using Microsoft.SemanticKernel.Planners;

Check warning on line 4 in webapi/Models/Response/ProposedPlan.cs

View workflow job for this annotation

GitHub Actions / check-format

Using directive is unnecessary.
using Microsoft.SemanticKernel.Planning;

namespace CopilotChat.WebApi.Models.Response;

Expand Down
95 changes: 50 additions & 45 deletions webapi/Plugins/Chat/ChatPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.TemplateEngine.Basic;
using ChatCompletionContextMessages = Microsoft.SemanticKernel.ChatCompletion.ChatHistory;
using CopilotChatMessage = CopilotChat.WebApi.Models.Storage.CopilotChatMessage;

Expand Down Expand Up @@ -149,14 +148,15 @@ private async Task<string> ExtractUserIntentAsync(KernelArguments kernelArgument
intentExtractionArugments.Add("tokenLimit", historyTokenBudget);

Check warning on line 148 in webapi/Plugins/Chat/ChatPlugin.cs

View workflow job for this annotation

GitHub Actions / Spell Check with Typos

"Arugments" should be "Arguments".
intentExtractionArugments.Add("knowledgeCutoff", this._promptOptions.KnowledgeCutoffDate);

Check warning on line 149 in webapi/Plugins/Chat/ChatPlugin.cs

View workflow job for this annotation

GitHub Actions / Spell Check with Typos

"Arugments" should be "Arguments".

var completionFunction = this._kernel.CreateSemanticFunction(
var completionFunction = this._kernel.CreateFunctionFromPrompt(
this._promptOptions.SystemIntentExtraction,
pluginName: nameof(ChatPlugin),
this.CreateIntentCompletionSettings(),
functionName: nameof(ChatPlugin),
description: "Complete the prompt.");

var result = await completionFunction.InvokeAsync(
this._kernel,
intentExtractionArugments,

Check warning on line 159 in webapi/Plugins/Chat/ChatPlugin.cs

View workflow job for this annotation

GitHub Actions / Spell Check with Typos

"Arugments" should be "Arguments".
this.CreateIntentCompletionSettings(),
cancellationToken
);

Expand Down Expand Up @@ -189,14 +189,15 @@ private async Task<string> ExtractAudienceAsync(KernelArguments kernelArguments,
var audienceExtractionArguments = new KernelArguments(kernelArguments);
kernelArguments.Add("tokenLimit", historyTokenBudget);

var completionFunction = this._kernel.CreateSemanticFunction(
var completionFunction = this._kernel.CreateFunctionFromPrompt(
this._promptOptions.SystemAudienceExtraction,
pluginName: nameof(ChatPlugin),
this.CreateIntentCompletionSettings(),
functionName: nameof(ChatPlugin),
description: "Complete the prompt.");

var result = await completionFunction.InvokeAsync(
this._kernel,
audienceExtractionArguments,
this.CreateIntentCompletionSettings(),
cancellationToken
);

Expand Down Expand Up @@ -297,8 +298,7 @@ private async Task<string> GetAllowedChatHistoryAsync(
}
}

allottedChatHistory.Reverse();
chatHistory?.AddRange(allottedChatHistory);
chatHistory?.AddRange(allottedChatHistory.Reverse());

return $"Chat history:\n{historyText.Trim()}";
}
Expand Down Expand Up @@ -331,7 +331,7 @@ public async Task<KernelArguments> ChatAsync(
chatContext.Add("knowledgeCutoff", this._promptOptions.KnowledgeCutoffDate);

CopilotChatMessage chatMessage = await this.GetChatResponseAsync(chatId, userId, kernelArguments, newUserMessage, cancellationToken);
kernelArguments.Add(KernelArguments.InputParameterName, chatMessage.Content);
kernelArguments.Add("input", chatMessage.Content);

if (chatMessage.TokenUsage != null)
{
Expand Down Expand Up @@ -424,51 +424,53 @@ await this.SaveNewResponseAsync(
// Render system instruction components and create the meta-prompt template
var systemInstructions = await AsyncUtils.SafeInvokeAsync(
() => this.RenderSystemInstructions(chatId, kernelArguments, cancellationToken), nameof(RenderSystemInstructions));
var chatCompletion = this._kernel.GetRequiredService<IChatCompletion>();
var promptTemplate = chatCompletion.CreateNewChat(systemInstructions);
var chatCompletion = this._kernel.GetRequiredService<IChatCompletionService>();
var chatHistory = new ChatHistory(systemInstructions);
var reply = await chatCompletion.GetChatMessageContentAsync(chatHistory, null, this._kernel, cancellationToken);
chatHistory.Add(reply);
string chatHistoryString = "";

// Add original user input that prompted plan template
promptTemplate.AddUserMessage(deserializedPlan.OriginalUserInput);
chatHistory.AddUserMessage(deserializedPlan.OriginalUserInput);
chatHistoryString += "\n" + PromptUtils.FormatChatHistoryMessage(CopilotChatMessage.AuthorRoles.User, deserializedPlan.OriginalUserInput);

// Add bot message proposal as prompt context message
chatContext.Add("planFunctions", this._externalInformationPlugin.FormattedFunctionsString(deserializedPlan.Plan));
var promptTemplateFactory = new BasicPromptTemplateFactory();
var proposedPlanTemplate = promptTemplateFactory.Create(this._promptOptions.ProposedPlanBotMessage, new PromptTemplateConfig());
var proposedPlanBotMessage = await proposedPlanTemplate.RenderAsync(kernelArguments, cancellationToken);
promptTemplate.AddAssistantMessage(proposedPlanBotMessage);
var promptTemplateFactory = new KernelPromptTemplateFactory();
var proposedPlanTemplate = promptTemplateFactory.Create(new PromptTemplateConfig(this._promptOptions.ProposedPlanBotMessage));
var proposedPlanBotMessage = await proposedPlanTemplate.RenderAsync(this._kernel, kernelArguments, cancellationToken);
chatHistory.AddAssistantMessage(proposedPlanBotMessage);
chatHistoryString += "\n" + PromptUtils.FormatChatHistoryMessage(CopilotChatMessage.AuthorRoles.Bot, proposedPlanBotMessage);

// Add user approval message as prompt context message
promptTemplate.AddUserMessage("Yes, proceed");
chatHistory.AddUserMessage("Yes, proceed");
chatHistoryString += "\n" + PromptUtils.FormatChatHistoryMessage(CopilotChatMessage.AuthorRoles.User, "Yes, proceed");

// Add user intent behind plan
// TODO: [Issue #51] Consider regenerating user intent if plan was modified
promptTemplate.AddSystemMessage(deserializedPlan.UserIntent);
chatHistory.AddSystemMessage(deserializedPlan.UserIntent);

// Render system supplement to help guide model in using data.
var promptSupplementTemplate = promptTemplateFactory.Create(this._promptOptions.PlanResultsDescription, new PromptTemplateConfig());
var promptSupplement = await promptSupplementTemplate.RenderAsync(kernelArguments, cancellationToken);
var promptSupplementTemplate = promptTemplateFactory.Create(new PromptTemplateConfig(this._promptOptions.PlanResultsDescription));
var promptSupplement = await promptSupplementTemplate.RenderAsync(this._kernel, kernelArguments, cancellationToken);

// Calculate remaining token budget and execute plan
await this.UpdateBotResponseStatusOnClientAsync(chatId, "Executing plan", cancellationToken);
var remainingTokenBudget = this.GetChatContextTokenLimit(promptTemplate) - TokenUtils.GetContextMessageTokenCount(AuthorRole.System, promptSupplement);
var remainingTokenBudget = this.GetChatContextTokenLimit(chatHistory) - TokenUtils.GetContextMessageTokenCount(AuthorRole.System, promptSupplement);

try
{
var planResult = await this.AcquireExternalInformationAsync(kernelArguments, deserializedPlan.UserIntent, remainingTokenBudget, cancellationToken, deserializedPlan.Plan);
promptTemplate.AddSystemMessage(planResult);
chatHistory.AddSystemMessage(planResult);

// Calculate token usage of prompt template
chatContext.Add(TokenUtils.GetFunctionKey(this._logger, "SystemMetaPrompt")!, TokenUtils.GetContextMessagesTokenCount(promptTemplate).ToString(CultureInfo.CurrentCulture));
chatContext.Add(TokenUtils.GetFunctionKey(this._logger, "SystemMetaPrompt")!, TokenUtils.GetContextMessagesTokenCount(chatHistory).ToString(CultureInfo.CurrentCulture));

// TODO: [Issue #150, sk#2106] Accommodate different planner contexts once core team finishes work to return prompt and token usage.
var plannerDetails = new SemanticDependency<PlanExecutionMetadata>(planResult, null, deserializedPlan.Type.ToString());

// Get bot response and stream to client
var promptView = new BotResponsePrompt(systemInstructions, "", deserializedPlan.UserIntent, "", plannerDetails, chatHistoryString, promptTemplate);
var promptView = new BotResponsePrompt(systemInstructions, "", deserializedPlan.UserIntent, "", plannerDetails, chatHistoryString, chatHistory);
chatMessage = await this.HandleBotResponseAsync(chatId, userId, kernelArguments, promptView, cancellationToken);

if (chatMessage.TokenUsage != null)
Expand Down Expand Up @@ -496,7 +498,7 @@ await this.SaveNewResponseAsync(
throw new KernelException("Failed to process plan.", ex);
}

kernelArguments.Add(KernelArguments.InputParameterName, chatMessage.Content);
kernelArguments.Add("input", chatMessage.Content);
}
else
{
Expand All @@ -520,8 +522,10 @@ private async Task<CopilotChatMessage> GetChatResponseAsync(string chatId, strin
// Render system instruction components and create the meta-prompt template
var systemInstructions = await AsyncUtils.SafeInvokeAsync(
() => this.RenderSystemInstructions(chatId, kernelArguments, cancellationToken), nameof(RenderSystemInstructions));
var chatCompletion = this._kernel.GetRequiredService<IChatCompletion>();
var promptTemplate = chatCompletion.CreateNewChat(systemInstructions);
var chatCompletion = this._kernel.GetRequiredService<IChatCompletionService>();
var chatHistory = new ChatHistory(systemInstructions);
var reply = await chatCompletion.GetChatMessageContentAsync(chatHistory, null, this._kernel, cancellationToken);
chatHistory.Add(reply);

// Bypass audience extraction if Auth is disabled
var audience = string.Empty;
Expand All @@ -531,18 +535,18 @@ private async Task<CopilotChatMessage> GetChatResponseAsync(string chatId, strin
await this.UpdateBotResponseStatusOnClientAsync(chatId, "Extracting audience", cancellationToken);
audience = await AsyncUtils.SafeInvokeAsync(
() => this.GetAudienceAsync(kernelArguments, cancellationToken), nameof(GetAudienceAsync));
promptTemplate.AddSystemMessage(audience);
chatHistory.AddSystemMessage(audience);
}

// Extract user intent from the conversation history.
await this.UpdateBotResponseStatusOnClientAsync(chatId, "Extracting user intent", cancellationToken);
var userIntent = await AsyncUtils.SafeInvokeAsync(
() => this.GetUserIntentAsync(kernelArguments, cancellationToken), nameof(GetUserIntentAsync));
promptTemplate.AddSystemMessage(userIntent);
chatHistory.AddSystemMessage(userIntent);

// Calculate the remaining token budget.
await this.UpdateBotResponseStatusOnClientAsync(chatId, "Calculating remaining token budget", cancellationToken);
var remainingTokenBudget = this.GetChatContextTokenLimit(promptTemplate, userMessage.ToFormattedString());
var remainingTokenBudget = this.GetChatContextTokenLimit(chatHistory, userMessage.ToFormattedString());

// Acquire external information from planner
await this.UpdateBotResponseStatusOnClientAsync(chatId, "Acquiring external information from planner", cancellationToken);
Expand Down Expand Up @@ -586,28 +590,28 @@ private async Task<CopilotChatMessage> GetChatResponseAsync(string chatId, strin

if (!string.IsNullOrWhiteSpace(memoryText))
{
promptTemplate.AddSystemMessage(memoryText);
chatHistory.AddSystemMessage(memoryText);
}

// Fill in the chat history with remaining token budget.
string chatHistory = string.Empty;
var chatHistoryTokenBudget = remainingTokenBudget - TokenUtils.GetContextMessageTokenCount(AuthorRole.System, memoryText) - TokenUtils.GetContextMessageTokenCount(AuthorRole.System, planResult);
string allowedChatHistory = string.Empty;
var allowedChatHistoryTokenBudget = remainingTokenBudget - TokenUtils.GetContextMessageTokenCount(AuthorRole.System, memoryText) - TokenUtils.GetContextMessageTokenCount(AuthorRole.System, planResult);

// Append previous messages
await this.UpdateBotResponseStatusOnClientAsync(chatId, "Extracting chat history", cancellationToken);
chatHistory = await this.GetAllowedChatHistoryAsync(chatId, chatHistoryTokenBudget, promptTemplate, cancellationToken);
allowedChatHistory = await this.GetAllowedChatHistoryAsync(chatId, allowedChatHistoryTokenBudget, chatHistory, cancellationToken);

// Append the plan result last, if exists, to imply precedence.
if (!string.IsNullOrWhiteSpace(planResult))
{
promptTemplate.AddSystemMessage(planResult);
chatHistory.AddSystemMessage(planResult);
}

// Calculate token usage of prompt template
kernelArguments.Add(TokenUtils.GetFunctionKey(this._logger, "SystemMetaPrompt")!, TokenUtils.GetContextMessagesTokenCount(promptTemplate).ToString(CultureInfo.CurrentCulture));
kernelArguments.Add(TokenUtils.GetFunctionKey(this._logger, "SystemMetaPrompt")!, TokenUtils.GetContextMessagesTokenCount(chatHistory).ToString(CultureInfo.CurrentCulture));

// Stream the response to the client
var promptView = new BotResponsePrompt(systemInstructions, audience, userIntent, memoryText, plannerDetails, chatHistory, promptTemplate);
var promptView = new BotResponsePrompt(systemInstructions, audience, userIntent, memoryText, plannerDetails, allowedChatHistory, chatHistory);
return await this.HandleBotResponseAsync(chatId, userId, kernelArguments, promptView, cancellationToken, citationMap.Values.AsEnumerable());
}

Expand All @@ -622,10 +626,10 @@ private async Task<string> RenderSystemInstructions(string chatId, KernelArgumen
// Render system instruction components
await this.UpdateBotResponseStatusOnClientAsync(chatId, "Initializing prompt", cancellationToken);

var promptTemplateFactory = new BasicPromptTemplateFactory();
var template = promptTemplateFactory.Create(this._promptOptions.SystemPersona, new PromptTemplateConfig());
var promptTemplateFactory = new KernelPromptTemplateFactory();
var template = promptTemplateFactory.Create(new PromptTemplateConfig(this._promptOptions.SystemPersona));

return await template.RenderAsync(kernelArguments, cancellationToken);
return await template.RenderAsync(this._kernel, kernelArguments, cancellationToken);
}

/// <summary>
Expand Down Expand Up @@ -746,7 +750,7 @@ private async Task<string> AcquireExternalInformationAsync(KernelArguments kerne
planArguments.Add("tokenLimit", tokenLimit.ToString(new NumberFormatInfo()));
return plan is not null
? await this._externalInformationPlugin.ExecutePlanAsync(planArguments, plan, cancellationToken)
: await this._externalInformationPlugin.InvokePlannerAsync(userIntent, planArguments, cancellationToken);
: await this._externalInformationPlugin.InvokePlannerAsync(this._kernel, userIntent, planArguments, cancellationToken);
}

/// <summary>
Expand Down Expand Up @@ -934,11 +938,12 @@ private async Task<CopilotChatMessage> StreamResponseToClientAsync(
IEnumerable<CitationSource>? citations = null)
{
// Create the stream
var chatCompletion = this._kernel.GetRequiredService<IChatCompletion>();
var chatCompletion = this._kernel.GetRequiredService<IChatCompletionService>();
var stream =
chatCompletion.GenerateMessageStreamAsync(
chatCompletion.GetStreamingChatMessageContentsAsync(
prompt.MetaPromptTemplate,
this.CreateChatRequestSettings(),
this._kernel,
cancellationToken);

// Create message on client
Expand All @@ -952,7 +957,7 @@ private async Task<CopilotChatMessage> StreamResponseToClientAsync(
);

// Stream the message to the client
await foreach (string contentPiece in stream)
await foreach (StreamingChatMessageContent contentPiece in stream)
{
chatMessage.Content += contentPiece;
await this.UpdateMessageOnClient(chatMessage, cancellationToken);
Expand Down
Loading

0 comments on commit fbaae8c

Please sign in to comment.