Closed
Description
Describe the bug
Semantic Kernel attempts to call a native function with a typed array for a parameter with the stringified JSON of its content rather than the deserialized array. This only seems to happen if the array type has an enum property.
To Reproduce
Create a Semantic Kernel project with the following Program.cs:
using System.ComponentModel;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
string model = "gpt-4o";
Console.Write("Enter your OpenAI API key: ");
string apiKey = Console.ReadLine();
Console.Write("Enter your OpenAI OrgId: ");
string orgId = Console.ReadLine();
IKernelBuilder builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion(model, apiKey, orgId, null, new HttpClient(new LoggingHttpClientHandler()));
Kernel kernel = builder.Build();
kernel.ImportPluginFromType<MyPlugin>();
OpenAIPromptExecutionSettings settings =
new() { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() };
IChatCompletionService chatCompletionService =
kernel.GetRequiredService<IChatCompletionService>();
ChatHistory chatHistory = [];
chatHistory.AddUserMessage("Set Item1 to 5.");
foreach (var content in await chatCompletionService.GetChatMessageContentsAsync(chatHistory, settings, kernel))
{
Console.WriteLine(content.Content);
}
enum ItemName
{
Item1,
Item2,
Item3
}
class Item
{
[Description("The name.")]
public ItemName Name { get; set; }
[Description("The value.")]
public int Value { get; set; }
}
class MyPlugin
{
[KernelFunction]
[Description("Sets the values of the specified items.")]
public Task SetItemValues(Kernel kernel, Item[] items)
{
foreach (Item item in items)
{
Console.WriteLine($"Setting {item.Name} to {item.Value}!");
}
return Task.CompletedTask;
}
}
class LoggingHttpClientHandler : HttpClientHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
string content;
if (request.Content is not null)
{
content = await request.Content.ReadAsStringAsync(cancellationToken);
Console.WriteLine(content);
}
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
MemoryStream responseStream = new(await response.Content.ReadAsByteArrayAsync(cancellationToken));
Console.WriteLine(new StreamReader(responseStream).ReadToEnd());
responseStream.Position = 0;
response.Content = new StreamContent(responseStream);
return response;
}
}
When you run this program, observe that the function parameters from OpenAI are properly formed, but Semantic Kernel tries to call SetItemValues with a stringified version of the JSON rather than the deserialized Item list.
Expected behavior
MyPlugin.SetItemValues gets called with an array of 1 Item
Platform
- Language: C#
- Source: NuGet package version 1.39.0
- AI model: OpenAI:GPT-4o
- IDE: Visual Studio
- OS: Windows, Mac