mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
e489ac0fa3
* Fix checkpoint JSON deserialization with out-of-order metadata properties (#2962) * Simplify: propagate AllowOutOfOrderMetadataProperties from incoming JsonSerializerOptions
78 lines
2.9 KiB
C#
78 lines
2.9 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
using System;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization.Metadata;
|
|
|
|
namespace Microsoft.Agents.AI.Workflows.Checkpointing;
|
|
|
|
internal sealed class JsonMarshaller : IWireMarshaller<JsonElement>
|
|
{
|
|
private readonly JsonSerializerOptions _internalOptions;
|
|
private readonly JsonSerializerOptions? _externalOptions;
|
|
|
|
public JsonMarshaller(JsonSerializerOptions? serializerOptions = null)
|
|
{
|
|
this._internalOptions = new JsonSerializerOptions(WorkflowsJsonUtilities.DefaultOptions)
|
|
{
|
|
// Propagate from the user-provided options if set; enables support for databases
|
|
// like PostgreSQL jsonb that do not preserve property order.
|
|
AllowOutOfOrderMetadataProperties = serializerOptions?.AllowOutOfOrderMetadataProperties is true,
|
|
};
|
|
|
|
this._internalOptions.Converters.Add(new PortableValueConverter(this));
|
|
this._internalOptions.Converters.Add(new ExecutorIdentityConverter());
|
|
this._internalOptions.Converters.Add(new ScopeKeyConverter());
|
|
this._internalOptions.Converters.Add(new EdgeIdConverter());
|
|
this._internalOptions.Converters.Add(new CheckpointInfoConverter());
|
|
|
|
this._externalOptions = serializerOptions;
|
|
}
|
|
|
|
private JsonTypeInfo LookupTypeInfo(Type type)
|
|
{
|
|
if (!this._internalOptions.TryGetTypeInfo(type, out JsonTypeInfo? typeInfo))
|
|
{
|
|
if (this._externalOptions is null ||
|
|
!this._externalOptions.TryGetTypeInfo(type, out typeInfo))
|
|
{
|
|
throw new InvalidOperationException($"No JSON type info is available for type '{type}'.");
|
|
}
|
|
}
|
|
|
|
return typeInfo;
|
|
}
|
|
|
|
public JsonElement Marshal(object value, Type type)
|
|
=> JsonSerializer.SerializeToElement(value, this.LookupTypeInfo(type));
|
|
|
|
public JsonElement Marshal<TValue>(TValue value)
|
|
=> JsonSerializer.SerializeToElement(value, this.LookupTypeInfo(typeof(TValue)));
|
|
|
|
public TValue Marshal<TValue>(JsonElement data)
|
|
{
|
|
object value = data.Deserialize(this.LookupTypeInfo(typeof(TValue))) ??
|
|
throw new InvalidOperationException($"Could not deserialize the value as the expected type {typeof(TValue)}.");
|
|
|
|
if (value is TValue typedValue)
|
|
{
|
|
return typedValue;
|
|
}
|
|
|
|
throw new InvalidOperationException($"Deserialized value is not of the expected type {typeof(TValue)}.");
|
|
}
|
|
|
|
public object Marshal(Type targetType, JsonElement data)
|
|
{
|
|
object value = data.Deserialize(this.LookupTypeInfo(targetType)) ??
|
|
throw new InvalidOperationException($"Could not deserialize the value as the expected type {targetType}.");
|
|
|
|
if (targetType.IsInstanceOfType(value))
|
|
{
|
|
return value;
|
|
}
|
|
|
|
throw new InvalidOperationException($"Deserialized value is not of the expected type {targetType}.");
|
|
}
|
|
}
|