mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
The `sessionId`, an optional parameter when starting a new session when running a workflow is an arbitrary string. This allows consumers to support whatever ids are needed by other systems, but can result in errors when an OS special or forbidden character is included. The fix is to escape the paths, in a 1:1 manner. We rely on EncodeDataString to do this. * Also modifies the index file to make it easier to determine what the name of the file on disk is for a given `sessionId`.
110 lines
5.0 KiB
C#
110 lines
5.0 KiB
C#
// 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.Extensions.AI;
|
|
|
|
namespace Microsoft.Agents.AI.Workflows;
|
|
|
|
/// <summary>Provides a collection of utility methods for working with JSON data in the context of workflows.</summary>
|
|
internal static partial class WorkflowsJsonUtilities
|
|
{
|
|
/// <summary>
|
|
/// Gets the <see cref="JsonSerializerOptions"/> singleton used as the default in JSON serialization operations.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// For Native AOT or applications disabling <see cref="JsonSerializer.IsReflectionEnabledByDefault"/>, this instance
|
|
/// includes source generated contracts for all common exchange types contained in this library.
|
|
/// </para>
|
|
/// <para>
|
|
/// It additionally turns on the following settings:
|
|
/// <list type="number">
|
|
/// <item>Enables <see cref="JsonSerializerDefaults.Web"/> defaults.</item>
|
|
/// <item>Enables <see cref="JsonIgnoreCondition.WhenWritingNull"/> as the default ignore condition for properties.</item>
|
|
/// <item>Enables <see cref="JsonNumberHandling.AllowReadingFromString"/> as the default number handling for number types.</item>
|
|
/// </list>
|
|
/// </para>
|
|
/// </remarks>
|
|
public static JsonSerializerOptions DefaultOptions { get; } = CreateDefaultOptions();
|
|
|
|
public static JsonElement Serialize(this IEnumerable<ChatMessage> messages) =>
|
|
JsonSerializer.SerializeToElement(messages, DefaultOptions.GetTypeInfo(typeof(IEnumerable<ChatMessage>)));
|
|
|
|
public static List<ChatMessage> DeserializeMessages(this JsonElement element) =>
|
|
(List<ChatMessage>?)element.Deserialize(DefaultOptions.GetTypeInfo(typeof(List<ChatMessage>))) ?? [];
|
|
|
|
/// <summary>
|
|
/// Creates default options to use for agents-related serialization.
|
|
/// </summary>
|
|
/// <returns>The configured options.</returns>
|
|
[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))]
|
|
|
|
// 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;
|
|
}
|