-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
.Net: BugFix Serializing and Deserializing ChatHistory with ToolCalli…
…ng details Update OpenAI Connector to use FunctionToolCallsProperty and add ChatHistoryTests (#4358) Serializing the ToolCalls was losing the details about Name and Arguments, and serializing this lack of content back was rendering ToolCalls as an invalid history message and giving the Issue Error. Resolves #4336 Next PR, moving the Integration Tests as Unit Tests ## Summary This pull request updates the OpenAI Connector to use the FunctionToolCallsProperty metadata key instead of the ToolCallsProperty metadata key. This change allows for the use of a list of ChatCompletionsFunctionToolCall objects instead of ChatCompletionsToolCall objects. Additionally, a new integration test, ChatHistoryTests.cs, is added to the IntegrationTests/Connectors/OpenAI directory. The test file contains tests for the ChatHistory feature of the OpenAI Connector, ensuring that the feature returns the expected results and handles errors correctly. ## Changes - Update ClientCore.cs to use FunctionToolCallsProperty instead of ToolCallsProperty - Update OpenAIChatMessageContent.cs to use FunctionToolCallsProperty instead of ToolCallsProperty - Add ChatHistoryTests.cs to IntegrationTests/Connectors/OpenAI directory - Implement tests for ChatHistory feature of OpenAI Connector - Dispose of logger and test output helper in ChatHistoryTests.cs --- *Powered by [Microsoft Semantic Kernel](https://github.com/microsoft/semantic-kernel)*
- Loading branch information
1 parent
48a6223
commit 95a621a
Showing
3 changed files
with
123 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
dotnet/src/IntegrationTests/Connectors/OpenAI/ChatHistoryTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System; | ||
using System.ComponentModel; | ||
using System.Linq; | ||
using System.Net.Http; | ||
using System.Text.Json; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.SemanticKernel; | ||
using Microsoft.SemanticKernel.ChatCompletion; | ||
using Microsoft.SemanticKernel.Connectors.OpenAI; | ||
using SemanticKernel.IntegrationTests.TestSettings; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
|
||
namespace SemanticKernel.IntegrationTests.Connectors.OpenAI; | ||
|
||
public sealed class ChatHistoryTests : IDisposable | ||
{ | ||
private readonly IKernelBuilder _kernelBuilder; | ||
private readonly XunitLogger<Kernel> _logger; | ||
private readonly RedirectOutput _testOutputHelper; | ||
private readonly IConfigurationRoot _configuration; | ||
private static readonly JsonSerializerOptions s_jsonOptionsCache = new() { WriteIndented = true }; | ||
public ChatHistoryTests(ITestOutputHelper output) | ||
{ | ||
this._logger = new XunitLogger<Kernel>(output); | ||
this._testOutputHelper = new RedirectOutput(output); | ||
Console.SetOut(this._testOutputHelper); | ||
|
||
// Load configuration | ||
this._configuration = new ConfigurationBuilder() | ||
.AddJsonFile(path: "testsettings.json", optional: false, reloadOnChange: true) | ||
.AddJsonFile(path: "testsettings.development.json", optional: true, reloadOnChange: true) | ||
.AddEnvironmentVariables() | ||
.AddUserSecrets<OpenAICompletionTests>() | ||
.Build(); | ||
|
||
this._kernelBuilder = Kernel.CreateBuilder(); | ||
} | ||
|
||
[Fact] | ||
public async Task ItSerializesAndDeserializesChatHistoryAsync() | ||
{ | ||
// Arrange | ||
this._kernelBuilder.Services.AddSingleton<ILoggerFactory>(this._logger); | ||
var builder = this._kernelBuilder; | ||
this.ConfigureAzureOpenAIChatAsText(builder); | ||
builder.Plugins.AddFromType<FakePlugin>(); | ||
var kernel = builder.Build(); | ||
|
||
OpenAIPromptExecutionSettings settings = new() { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions }; | ||
ChatHistory history = new(); | ||
|
||
// Act | ||
history.AddUserMessage("Make me a special poem"); | ||
var historyBeforeJson = JsonSerializer.Serialize(history.ToList(), s_jsonOptionsCache); | ||
var service = kernel.GetRequiredService<IChatCompletionService>(); | ||
ChatMessageContent result = await service.GetChatMessageContentAsync(history, settings, kernel); | ||
history.AddUserMessage("Ok thank you"); | ||
|
||
ChatMessageContent resultOriginalWorking = await service.GetChatMessageContentAsync(history, settings, kernel); | ||
var historyJson = JsonSerializer.Serialize(history, s_jsonOptionsCache); | ||
var historyAfterSerialization = JsonSerializer.Deserialize<ChatHistory>(historyJson); | ||
var exception = await Record.ExceptionAsync(() => service.GetChatMessageContentAsync(historyAfterSerialization!, settings, kernel)); | ||
|
||
// Assert | ||
Assert.Null(exception); | ||
} | ||
|
||
private void ConfigureAzureOpenAIChatAsText(IKernelBuilder kernelBuilder) | ||
{ | ||
var azureOpenAIConfiguration = this._configuration.GetSection("Planners:AzureOpenAI").Get<AzureOpenAIConfiguration>(); | ||
|
||
Assert.NotNull(azureOpenAIConfiguration); | ||
Assert.NotNull(azureOpenAIConfiguration.ChatDeploymentName); | ||
Assert.NotNull(azureOpenAIConfiguration.ApiKey); | ||
Assert.NotNull(azureOpenAIConfiguration.Endpoint); | ||
Assert.NotNull(azureOpenAIConfiguration.ServiceId); | ||
|
||
kernelBuilder.AddAzureOpenAIChatCompletion( | ||
deploymentName: azureOpenAIConfiguration.ChatDeploymentName, | ||
modelId: azureOpenAIConfiguration.ChatModelId, | ||
endpoint: azureOpenAIConfiguration.Endpoint, | ||
apiKey: azureOpenAIConfiguration.ApiKey, | ||
serviceId: azureOpenAIConfiguration.ServiceId); | ||
} | ||
|
||
public class FakePlugin | ||
{ | ||
[KernelFunction, Description("creates a special poem")] | ||
public string CreateSpecialPoem() | ||
{ | ||
return "ABCDE"; | ||
} | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
this.Dispose(true); | ||
GC.SuppressFinalize(this); | ||
} | ||
|
||
private void Dispose(bool disposing) | ||
{ | ||
if (disposing) | ||
{ | ||
this._logger.Dispose(); | ||
this._testOutputHelper.Dispose(); | ||
} | ||
} | ||
} |