From 95bb00b2150eab27d15ea97c77c42c9f2dc90ff3 Mon Sep 17 00:00:00 2001 From: "L. Elaine Dazzio" <170764058+LEDazzio01@users.noreply.github.com> Date: Mon, 23 Feb 2026 18:01:29 -0500 Subject: [PATCH 1/2] fix: use HasSchema check in DetermineElementType to prevent empty records When parsing JSON arrays containing objects without a predefined schema, `DetermineElementType()` was creating a `VariableType` with an empty (non-null) schema via `targetType.Schema?.Select(...) ?? []`. This caused `ParseRecord` to take the schema-based parsing path, iterating over zero schema fields and silently discarding all JSON properties. The fix checks `targetType.HasSchema` and falls back to `VariableType.RecordType` (which has `Schema = null`) when no schema is defined, ensuring `ParseRecord` takes the dynamic `ParseValues()` path that preserves all JSON properties. Closes #4195 --- .../Extensions/JsonDocumentExtensions.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/JsonDocumentExtensions.cs b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/JsonDocumentExtensions.cs index 9d3c5e335d..e2b038bbd7 100644 --- a/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/JsonDocumentExtensions.cs +++ b/dotnet/src/Microsoft.Agents.AI.Workflows.Declarative/Extensions/JsonDocumentExtensions.cs @@ -111,7 +111,9 @@ VariableType DetermineElementType() VariableType? currentType = element.ValueKind switch { - JsonValueKind.Object => VariableType.Record(targetType.Schema?.Select(kvp => (kvp.Key, kvp.Value)) ?? []), + JsonValueKind.Object => targetType.HasSchema + ? VariableType.Record(targetType.Schema!.Select(kvp => (kvp.Key, kvp.Value))) + : VariableType.RecordType, JsonValueKind.String => typeof(string), JsonValueKind.True => typeof(bool), JsonValueKind.False => typeof(bool), From 7f3182f38583064a780a897e8084adc4371b1306 Mon Sep 17 00:00:00 2001 From: "L. Elaine Dazzio" <170764058+LEDazzio01@users.noreply.github.com> Date: Tue, 24 Feb 2026 17:47:37 -0500 Subject: [PATCH 2/2] test: add regression tests for schema-less JSON array-of-objects parsing (#4195) Add two regression tests to JsonDocumentExtensionsTests: 1. ParseRecord_ObjectWithArrayOfObjects_NoSchema_PreservesNestedProperties - Parses a JSON object containing an array of objects using VariableType.RecordType (no schema) and verifies that nested object properties (name, role) are preserved in each element. - This is the exact scenario from issue #4195 where objects in arrays were being returned as empty dictionaries. 2. ParseList_ArrayOfObjects_NoSchema_PreservesProperties - Parses a JSON array of objects directly via ParseList with VariableType.ListType (no schema) and verifies all properties are preserved. Both tests follow the existing Arrange/Act/Assert pattern and would have failed before the DetermineElementType() fix (empty dictionaries instead of populated ones). --- .../Extensions/JsonDocumentExtensionsTests.cs | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/JsonDocumentExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/JsonDocumentExtensionsTests.cs index bd86aa1958..fc03d17142 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/JsonDocumentExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/Extensions/JsonDocumentExtensionsTests.cs @@ -384,4 +384,79 @@ public void ParseList_Array_MixedTypes_Throws() // Act / Assert Assert.Throws(() => document.ParseList(typeof(int[]))); } + + /// + /// Regression test for #4195: When a JSON object contains an array of objects + /// and is parsed with VariableType.RecordType (no schema), the nested + /// object properties must be preserved. Before the fix, DetermineElementType() + /// created an empty-schema VariableType, causing ParseRecord to take the + /// ParseSchema path (zero fields) and return empty dictionaries. + /// + [Fact] + public void ParseRecord_ObjectWithArrayOfObjects_NoSchema_PreservesNestedProperties() + { + // Arrange + JsonDocument document = JsonDocument.Parse( + """ + { + "items": [ + { "name": "Alice", "role": "Engineer" }, + { "name": "Bob", "role": "Designer" }, + { "name": "Carol", "role": "PM" } + ] + } + """); + + // Act + Dictionary result = document.ParseRecord(VariableType.RecordType); + + // Assert + Assert.True(result.ContainsKey("items")); + List items = Assert.IsType>(result["items"]); + Assert.Equal(3, items.Count); + + Dictionary first = Assert.IsType>(items[0]); + Assert.Equal("Alice", first["name"]); + Assert.Equal("Engineer", first["role"]); + + Dictionary second = Assert.IsType>(items[1]); + Assert.Equal("Bob", second["name"]); + Assert.Equal("Designer", second["role"]); + + Dictionary third = Assert.IsType>(items[2]); + Assert.Equal("Carol", third["name"]); + Assert.Equal("PM", third["role"]); + } + + /// + /// Regression test for #4195: When a JSON array of objects is parsed directly + /// via ParseList with VariableType.ListType (no schema), all + /// object properties must be preserved in each element. + /// + [Fact] + public void ParseList_ArrayOfObjects_NoSchema_PreservesProperties() + { + // Arrange + JsonDocument document = JsonDocument.Parse( + """ + [ + { "name": "Alice", "role": "Engineer" }, + { "name": "Bob", "role": "Designer" } + ] + """); + + // Act + List result = document.ParseList(VariableType.ListType); + + // Assert + Assert.Equal(2, result.Count); + + Dictionary first = Assert.IsType>(result[0]); + Assert.Equal("Alice", first["name"]); + Assert.Equal("Engineer", first["role"]); + + Dictionary second = Assert.IsType>(result[1]); + Assert.Equal("Bob", second["name"]); + Assert.Equal("Designer", second["role"]); + } }