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), 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"]); + } }