// Copyright (c) Microsoft. All rights reserved. using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Agents.AI.Workflows.Checkpointing; using Microsoft.Agents.AI.Workflows.Execution; using Microsoft.Agents.AI.Workflows.Specialized; using Microsoft.Agents.AI.Workflows.Specialized.Magentic; using Microsoft.Extensions.AI; namespace Microsoft.Agents.AI.Workflows; /// Provides a collection of utility methods for working with JSON data in the context of workflows. internal static partial class WorkflowsJsonUtilities { /// /// Gets the singleton used as the default in JSON serialization operations. /// /// /// /// For Native AOT or applications disabling , this instance /// includes source generated contracts for all common exchange types contained in this library. /// /// /// It additionally turns on the following settings: /// /// Enables defaults. /// Enables as the default ignore condition for properties. /// Enables as the default number handling for number types. /// /// /// public static JsonSerializerOptions DefaultOptions { get; } = CreateDefaultOptions(); public static JsonElement Serialize(this IEnumerable messages) => JsonSerializer.SerializeToElement(messages, DefaultOptions.GetTypeInfo(typeof(IEnumerable))); public static List DeserializeMessages(this JsonElement element) => (List?)element.Deserialize(DefaultOptions.GetTypeInfo(typeof(List))) ?? []; /// /// Creates default options to use for agents-related serialization. /// /// The configured options. [UnconditionalSuppressMessage("ReflectionAnalysis", "IL3050:RequiresDynamicCode", Justification = "Converter is guarded by IsReflectionEnabledByDefault check.")] [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access", Justification = "Converter is guarded by IsReflectionEnabledByDefault check.")] private static JsonSerializerOptions CreateDefaultOptions() { // Copy the configuration from the source generated context. JsonSerializerOptions options = new(JsonContext.Default.Options); // Chain in the resolvers from both AgentAbstractionsJsonUtilities and our source generated context. // We want AgentAbstractionsJsonUtilities first to ensure any M.E.AI types are handled via its resolver. options.TypeInfoResolverChain.Clear(); options.TypeInfoResolverChain.Add(AgentAbstractionsJsonUtilities.DefaultOptions.TypeInfoResolver!); options.TypeInfoResolverChain.Add(JsonContext.Default.Options.TypeInfoResolver!); options.MakeReadOnly(); return options; } // Keep in sync with CreateDefaultOptions above. [JsonSourceGenerationOptions(JsonSerializerDefaults.Web, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, NumberHandling = JsonNumberHandling.AllowReadingFromString)] // Checkpointing Types [JsonSerializable(typeof(Checkpoint))] [JsonSerializable(typeof(CheckpointInfo))] [JsonSerializable(typeof(PortableValue))] [JsonSerializable(typeof(PortableMessageEnvelope))] [JsonSerializable(typeof(InMemoryCheckpointManager))] [JsonSerializable(typeof(CheckpointFileIndexEntry))] // Runtime State Types [JsonSerializable(typeof(ScopeKey))] [JsonSerializable(typeof(ScopeId))] [JsonSerializable(typeof(ExecutorIdentity))] [JsonSerializable(typeof(RunnerStateData))] // Workflow Representation Types [JsonSerializable(typeof(WorkflowInfo))] [JsonSerializable(typeof(EdgeConnection))] // Workflow-as-Agent [JsonSerializable(typeof(WorkflowChatHistoryProvider.StoreState))] [JsonSerializable(typeof(WorkflowSession.SessionState))] // Message Types [JsonSerializable(typeof(ChatMessage))] [JsonSerializable(typeof(ExternalRequest))] [JsonSerializable(typeof(ExternalResponse))] [JsonSerializable(typeof(TurnToken))] // Built-in Executor State Types [JsonSerializable(typeof(AIAgentHostState))] [JsonSerializable(typeof(HandoffSharedState))] [JsonSerializable(typeof(HandoffAgentHostState))] [JsonSerializable(typeof(MagenticPlanReviewRequest))] [JsonSerializable(typeof(MagenticPlanReviewResponse))] [JsonSerializable(typeof(MagenticTaskState))] [JsonSerializable(typeof(ResetChatSignal))] // Event Types //[JsonSerializable(typeof(WorkflowEvent))] // Currently cannot be serialized because it includes Exceptions. // We'll need a way to marshal this correctly in the AgentRuntime case. // For now this is okay, because we never serialize WorkflowEvents into // checkpoints. [JsonSerializable(typeof(JsonElement))] [ExcludeFromCodeCoverage] internal sealed partial class JsonContext : JsonSerializerContext; }