mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
.NET: Fix the ordering of chained resolvers in JsonSerializerOptions (#1974)
* Fix the ordering of chained resolvers in JsonSerializerOptions We want the resolvers from AIJsonUtilities to be used before the ones from the source generator, in case the source generator emits its own copy in that assembly for the M.E.AI types. * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update dotnet/src/Microsoft.Agents.AI/AgentJsonUtilities.cs * Update dotnet/src/Microsoft.Agents.AI.Mem0/Mem0JsonUtilities.cs Co-authored-by: westey <164392973+westey-m@users.noreply.github.com> * Remove unused using directive in Mem0JsonUtilities Removed unused using directive for Microsoft.Extensions.AI. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: westey <164392973+westey-m@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
cb50f3e070
commit
820c6afe09
@@ -50,12 +50,16 @@ public static partial class AgentAbstractionsJsonUtilities
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, // same as AIJsonUtilities
|
||||
};
|
||||
|
||||
// Chain with all supported types from Microsoft.Extensions.AI.Abstractions.
|
||||
// Chain in the resolvers from both AIJsonUtilities and our source generated context.
|
||||
// We want AIJsonUtilities first to ensure any M.E.AI types are handled via its resolver.
|
||||
options.TypeInfoResolverChain.Clear();
|
||||
options.TypeInfoResolverChain.Add(AIJsonUtilities.DefaultOptions.TypeInfoResolver!);
|
||||
options.TypeInfoResolverChain.Add(JsonContext.Default.Options.TypeInfoResolver!);
|
||||
|
||||
// If reflection-based serialization is enabled by default, this includes
|
||||
// the default type info resolver that utilizes reflection, but we need to manually
|
||||
// apply the same converter AIJsonUtilities adds for string-based enum serialization,
|
||||
// as that's not propagated as part of the resolver.
|
||||
options.TypeInfoResolverChain.Add(AIJsonUtilities.DefaultOptions.TypeInfoResolver!);
|
||||
if (JsonSerializer.IsReflectionEnabledByDefault)
|
||||
{
|
||||
options.Converters.Add(new JsonStringEnumConverter());
|
||||
|
||||
+6
@@ -17,7 +17,13 @@ internal static class ChatCompletionsJsonSerializerOptions
|
||||
private static JsonSerializerOptions Create()
|
||||
{
|
||||
JsonSerializerOptions options = new(ChatCompletionsJsonContext.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(ChatCompletionsJsonContext.Default.Options.TypeInfoResolver!);
|
||||
|
||||
options.MakeReadOnly();
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,13 @@ internal static class OpenAIHostingJsonUtilities
|
||||
private static JsonSerializerOptions CreateDefaultOptions()
|
||||
{
|
||||
JsonSerializerOptions options = new(OpenAIHostingJsonContext.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(OpenAIHostingJsonContext.Default.Options.TypeInfoResolver!);
|
||||
|
||||
options.MakeReadOnly();
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
namespace Microsoft.Agents.AI.Mem0;
|
||||
|
||||
@@ -44,8 +43,12 @@ public static partial class Mem0JsonUtilities
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, // same as in AIJsonUtilities
|
||||
};
|
||||
|
||||
// Chain with all supported types from Microsoft.Extensions.AI.Abstractions.
|
||||
options.TypeInfoResolverChain.Add(AIJsonUtilities.DefaultOptions.TypeInfoResolver!);
|
||||
// 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!);
|
||||
|
||||
if (JsonSerializer.IsReflectionEnabledByDefault)
|
||||
{
|
||||
options.Converters.Add(new JsonStringEnumConverter());
|
||||
|
||||
@@ -50,8 +50,11 @@ internal static partial class WorkflowsJsonUtilities
|
||||
// Copy the configuration from the source generated context.
|
||||
JsonSerializerOptions options = new(JsonContext.Default.Options);
|
||||
|
||||
// Chain with all supported types from Microsoft.Extensions.AI.Abstractions and Microsoft.Agents.AI.Abstractions.
|
||||
// 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;
|
||||
|
||||
@@ -44,8 +44,12 @@ internal static partial class AgentJsonUtilities
|
||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, // same as in AgentAbstractionsJsonUtilities and AIJsonUtilities
|
||||
};
|
||||
|
||||
// Chain with all supported types from Microsoft.Agents.AI.Abstractions.
|
||||
// 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!);
|
||||
|
||||
if (JsonSerializer.IsReflectionEnabledByDefault)
|
||||
{
|
||||
options.Converters.Add(new JsonStringEnumConverter());
|
||||
|
||||
+17
@@ -114,6 +114,23 @@ public class InMemoryChatMessageStoreTests
|
||||
Assert.Equal("B", newStore[1].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SerializeAndDeserializeWorksWithExperimentalContentTypesAsync()
|
||||
{
|
||||
var store = new InMemoryChatMessageStore
|
||||
{
|
||||
new ChatMessage(ChatRole.User, [new FunctionApprovalRequestContent("call123", new FunctionCallContent("call123", "some_func"))]),
|
||||
new ChatMessage(ChatRole.Assistant, [new FunctionApprovalResponseContent("call123", true, new FunctionCallContent("call123", "some_func"))])
|
||||
};
|
||||
|
||||
var jsonElement = store.Serialize();
|
||||
var newStore = new InMemoryChatMessageStore(jsonElement);
|
||||
|
||||
Assert.Equal(2, newStore.Count);
|
||||
Assert.IsType<FunctionApprovalRequestContent>(newStore[0].Contents[0]);
|
||||
Assert.IsType<FunctionApprovalResponseContent>(newStore[1].Contents[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AddMessagesAsyncWithEmptyMessagesDoesNotChangeStoreAsync()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user