// Copyright (c) Microsoft. All rights reserved. using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text.Json; using Microsoft.Agents.AI.Workflows.Declarative.Extensions; using Microsoft.PowerFx.Types; using Microsoft.Shared.Diagnostics; namespace Microsoft.Agents.AI.Workflows.Declarative.Kit; /// /// Extension helpers for converting instances (and collections containing them) /// into their normalized runtime representations (primarily primitives) ready for evaluation. /// public static class PortableValueExtensions { /// /// Normalizes all values in the provided dictionary. Each entry whose value is a /// is converted to its underlying normalized representation; non-PortableValue entries are preserved as-is. /// /// The source dictionary whose values may contain instances; may be null. /// /// A new dictionary with normalized values, or null if is null. /// Keys are copied unchanged. /// public static IDictionary? NormalizePortableValues(this IDictionary? source) { if (source is null) { return null; } return source.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.NormalizePortableValue()); } /// /// Normalizes an arbitrary value if it is a ; otherwise returns the value unchanged. /// /// The value to normalize; may be null or already a primitive/object. /// /// Null if is null; the normalized result if it is a ; /// otherwise the original . /// public static object? NormalizePortableValue(this object? value) => Throw.IfNull(value, nameof(value)) switch { null => null, JsonElement jsonValue => jsonValue.GetValue(), PortableValue portableValue => portableValue.Normalize(), _ => value, }; /// /// Converts a into a concrete representation suitable for evaluation. /// /// The portable value to normalize; cannot be null. /// /// A instance representing the underlying value. /// public static object? Normalize(this PortableValue value) => Throw.IfNull(value, nameof(value)).TypeId switch { _ when value.IsType(out string? stringValue) => stringValue, _ when value.IsSystemType(out bool? boolValue) => boolValue.Value, _ when value.IsSystemType(out int? intValue) => intValue.Value, _ when value.IsSystemType(out long? longValue) => longValue.Value, _ when value.IsSystemType(out decimal? decimalValue) => decimalValue.Value, _ when value.IsSystemType(out float? floatValue) => floatValue.Value, _ when value.IsSystemType(out double? doubleValue) => doubleValue.Value, _ when value.IsParentType(out IDictionary? recordValue) => recordValue.NormalizePortableValues(), _ when value.IsParentType(out IEnumerable? listValue) => listValue.NormalizePortableValues(), _ => throw new DeclarativeActionException($"Unsupported portable type: {value.TypeId.TypeName}"), }; private static Dictionary NormalizePortableValues(this IDictionary source) { return GetValues().ToDictionary(kvp => kvp.Key, kvp => kvp.Value); IEnumerable> GetValues() { foreach (DictionaryEntry entry in source) { yield return new KeyValuePair((string)entry.Key, entry.Value.NormalizePortableValue()); } } } private static object?[] NormalizePortableValues(this IEnumerable source) => source.Cast().Select(NormalizePortableValue).ToArray(); private static object? GetValue(this JsonElement element) => element.ValueKind switch { JsonValueKind.String => element.GetString(), JsonValueKind.True => true, JsonValueKind.False => false, JsonValueKind.Null => null, JsonValueKind.Number => element.TryGetInt64(out long longValue) ? longValue : element.GetDouble(), JsonValueKind.Object => element.EnumerateObject().ToDictionary(p => p.Name, p => p.Value.GetValue()), JsonValueKind.Array => element.EnumerateArray().Select(e => e.GetValue()).ToArray(), _ => throw new DeclarativeActionException($"Unsupported JSON value kind: {element.ValueKind}"), }; }