Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.Net: Fix mapping of the KernelParameterMetadata.IsRequired property #11309

Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ private static IReadOnlyList<KernelParameterMetadata> MapParameterMetadata(AIFun
return Array.Empty<KernelParameterMetadata>();
}

HashSet<string>? requiredParameters = GetRequiredParameterNames(aiFunction.JsonSchema);

List<KernelParameterMetadata> kernelParams = [];
var parameterInfos = aiFunction.UnderlyingMethod?.GetParameters().ToDictionary(p => p.Name!, StringComparer.Ordinal);
foreach (var param in properties.EnumerateObject())
Expand All @@ -76,7 +78,7 @@ private static IReadOnlyList<KernelParameterMetadata> MapParameterMetadata(AIFun
{
Description = param.Value.TryGetProperty("description", out JsonElement description) ? description.GetString() : null,
DefaultValue = param.Value.TryGetProperty("default", out JsonElement defaultValue) ? defaultValue : null,
IsRequired = param.Value.TryGetProperty("required", out JsonElement required) && required.GetBoolean(),
IsRequired = requiredParameters?.Contains(param.Name) ?? false,
ParameterType = paramInfo?.ParameterType,
Schema = param.Value.TryGetProperty("schema", out JsonElement schema)
? new KernelJsonSchema(schema)
Expand All @@ -86,4 +88,25 @@ private static IReadOnlyList<KernelParameterMetadata> MapParameterMetadata(AIFun

return kernelParams;
}

/// <summary>
/// Gets the names of the required parameters from the AI function's JSON schema.
/// </summary>
/// <param name="schema">The JSON schema of the AI function.</param>
/// <returns>The names of the required parameters.</returns>
private static HashSet<string>? GetRequiredParameterNames(JsonElement schema)
{
HashSet<string>? requiredParameterNames = null;

if (schema.TryGetProperty("required", out JsonElement requiredElement) && requiredElement.ValueKind == JsonValueKind.Array)
{
foreach (var node in requiredElement.EnumerateArray())
{
requiredParameterNames ??= [];
requiredParameterNames.Add(node.GetString()!);
}
}

return requiredParameterNames;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Linq;
using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Xunit;

namespace SemanticKernel.UnitTests.AI.ChatCompletion;

public class AIFunctionKernelFunctionTests
{
[Fact]
public void ShouldAssignIsRequiredParameterMetadataPropertyCorrectly()
{
// Arrange and Act
AIFunction aiFunction = AIFunctionFactory.Create((string p1, int? p2 = null) => p1);

AIFunctionKernelFunction sut = new(aiFunction);

// Assert
KernelParameterMetadata? p1Metadata = sut.Metadata.Parameters.FirstOrDefault(p => p.Name == "p1");
Assert.True(p1Metadata?.IsRequired);

KernelParameterMetadata? p2Metadata = sut.Metadata.Parameters.FirstOrDefault(p => p.Name == "p2");
Assert.False(p2Metadata?.IsRequired);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
</PackageReference>
<PackageReference Include="Microsoft.ML.Tokenizers" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
<PackageReference Include="Microsoft.Extensions.AI" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading