diff --git a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.Create.cs b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.Create.cs index c77e7dffb5b..17e5e4d5353 100644 --- a/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.Create.cs +++ b/src/Libraries/Microsoft.Extensions.AI.Abstractions/Utilities/AIJsonUtilities.Schema.Create.cs @@ -14,6 +14,7 @@ using System.Text.Json.Nodes; using System.Text.Json.Schema; using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Metadata; using System.Threading; using Microsoft.Shared.Diagnostics; @@ -289,6 +290,12 @@ JsonNode TransformSchemaNode(JsonSchemaExporterContext schemaExporterContext, Js objSchema.InsertAtStart(TypePropertyName, "string"); } + // Include a trivial items keyword if missing + if (ctx.TypeInfo.Kind is JsonTypeInfoKind.Enumerable && !objSchema.ContainsKey(ItemsPropertyName)) + { + objSchema.Add(ItemsPropertyName, new JsonObject()); + } + // Some consumers of the JSON schema, including Ollama as of v0.3.13, don't understand // schemas with "type": [...], and only understand "type" being a single value. // In certain configurations STJ represents .NET numeric types as ["string", "number"], which will then lead to an error. diff --git a/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Utilities/AIJsonUtilitiesTests.cs b/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Utilities/AIJsonUtilitiesTests.cs index acbb5515085..bcec2981c5b 100644 --- a/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Utilities/AIJsonUtilitiesTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.Abstractions.Tests/Utilities/AIJsonUtilitiesTests.cs @@ -170,6 +170,21 @@ public static void CreateJsonSchema_DefaultParameters_GeneratesExpectedJsonSchem AssertDeepEquals(expected, actual); } + [Fact] + public static void CreateJsonSchema_TrivialArray_GeneratesExpectedJsonSchema() + { + JsonElement expected = JsonDocument.Parse(""" + { + "type": "array", + "items": {} + } + """).RootElement; + + JsonElement actual = AIJsonUtilities.CreateJsonSchema(typeof(object[]), serializerOptions: JsonContext.Default.Options); + + AssertDeepEquals(expected, actual); + } + [Fact] public static void CreateJsonSchema_OverriddenParameters_GeneratesExpectedJsonSchema() { @@ -1326,6 +1341,7 @@ private class DerivedAIContent : AIContent [JsonSerializable(typeof(DerivedAIContent))] [JsonSerializable(typeof(MyPoco))] [JsonSerializable(typeof(MyEnumValue?))] + [JsonSerializable(typeof(object[]))] private partial class JsonContext : JsonSerializerContext; private static bool DeepEquals(JsonElement element1, JsonElement element2)