diff --git a/dotnet/src/InternalUtilities/src/Schema/KernelJsonSchemaBuilder.cs b/dotnet/src/InternalUtilities/src/Schema/KernelJsonSchemaBuilder.cs index 82f82895b96b..f96d60ef349d 100644 --- a/dotnet/src/InternalUtilities/src/Schema/KernelJsonSchemaBuilder.cs +++ b/dotnet/src/InternalUtilities/src/Schema/KernelJsonSchemaBuilder.cs @@ -67,7 +67,10 @@ private static JsonSerializerOptions GetDefaultOptions() { JsonSerializerOptions options = new() { - TypeInfoResolver = new DefaultJsonTypeInfoResolver(), + TypeInfoResolver = new DefaultJsonTypeInfoResolver + { + Modifiers = { ExcludeReadOnlyProperties } + }, Converters = { new JsonStringEnumConverter() }, }; options.MakeReadOnly(); @@ -76,4 +79,19 @@ private static JsonSerializerOptions GetDefaultOptions() return s_options; } + + private static void ExcludeReadOnlyProperties(JsonTypeInfo typeInfo) + { + if (typeInfo.Kind != JsonTypeInfoKind.Object) return; + + for (int i = 0; i < typeInfo.Properties.Count; i++) + { + var property = typeInfo.Properties[i]; + + if (property.Set == null) + { + typeInfo.Properties.RemoveAt(i--); + } + } + } } diff --git a/dotnet/src/SemanticKernel.UnitTests/Functions/KernelJsonSchemaTests.cs b/dotnet/src/SemanticKernel.UnitTests/Functions/KernelJsonSchemaTests.cs index 55ca99e9c703..87d096a602fa 100644 --- a/dotnet/src/SemanticKernel.UnitTests/Functions/KernelJsonSchemaTests.cs +++ b/dotnet/src/SemanticKernel.UnitTests/Functions/KernelJsonSchemaTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. using System; +using System.ComponentModel; using System.Text; using System.Text.Json; using Microsoft.SemanticKernel; @@ -91,6 +92,39 @@ public void ItThrowsOnInvalidJson() Assert.ThrowsAny(() => KernelJsonSchema.Parse(Encoding.UTF8.GetBytes(InvalidJsonSchema))); } + [Fact] + public void ItShouldExcludeReadOnlyPropertiesFromSchema() + { + var function = KernelFunctionFactory.CreateFromMethod( + (MyComplexType input) => { }, + "TestFunction"); + + var schema = function.Metadata.Parameters[0].Schema; + var jsonSchemaString = schema?.ToString(); + + Assert.NotNull(jsonSchemaString); + Assert.Contains("Status", jsonSchemaString); + Assert.DoesNotContain("Derived", jsonSchemaString); + } + + /// + /// A helper class specific to this test case. + /// Used to verify that read-only properties are ignored by the schema generator. + /// + private class MyComplexType + { + [Description("The current status of the user account")] + public MyStatus Status { get; set; } + + public string Derived => $"Status is {Status}"; + } + + private enum MyStatus + { + Active, + Inactive + } + // TODO: KernelJsonSchema currently validates that the input is valid JSON but not that it's valid JSON schema. //[Theory] //[InlineData("{ \"type\":\"invalid\" }")]