|
3 | 3 |
|
4 | 4 | using System; |
5 | 5 | using System.Collections.Generic; |
6 | | -using System.Diagnostics.CodeAnalysis; |
7 | 6 | using System.Reflection; |
8 | 7 | using System.Runtime.CompilerServices; |
9 | 8 | using System.Text; |
@@ -38,6 +37,9 @@ public sealed partial class OpenAIChatClient : IChatClient |
38 | 37 | /// <summary>The underlying <see cref="ChatClient" />.</summary> |
39 | 38 | private readonly ChatClient _chatClient; |
40 | 39 |
|
| 40 | + /// <summary>The <see cref="JsonSerializerOptions"/> use for any serialization activities related to tool call arguments and results.</summary> |
| 41 | + private JsonSerializerOptions _toolCallJsonSerializerOptions = AIJsonUtilities.DefaultOptions; |
| 42 | + |
41 | 43 | /// <summary>Initializes a new instance of the <see cref="OpenAIChatClient"/> class for the specified <see cref="OpenAIClient"/>.</summary> |
42 | 44 | /// <param name="openAIClient">The underlying client.</param> |
43 | 45 | /// <param name="modelId">The model to use.</param> |
@@ -80,7 +82,11 @@ public OpenAIChatClient(ChatClient chatClient) |
80 | 82 | } |
81 | 83 |
|
82 | 84 | /// <summary>Gets or sets <see cref="JsonSerializerOptions"/> to use for any serialization activities related to tool call arguments and results.</summary> |
83 | | - public JsonSerializerOptions? ToolCallJsonSerializerOptions { get; set; } |
| 85 | + public JsonSerializerOptions ToolCallJsonSerializerOptions |
| 86 | + { |
| 87 | + get => _toolCallJsonSerializerOptions; |
| 88 | + set => _toolCallJsonSerializerOptions = Throw.IfNull(value); |
| 89 | + } |
84 | 90 |
|
85 | 91 | /// <inheritdoc /> |
86 | 92 | public ChatClientMetadata Metadata { get; } |
@@ -593,7 +599,7 @@ private sealed class OpenAIChatToolJson |
593 | 599 | { |
594 | 600 | try |
595 | 601 | { |
596 | | - result = JsonSerializer.Serialize(resultContent.Result, JsonContext.GetTypeInfo(typeof(object), ToolCallJsonSerializerOptions)); |
| 602 | + result = JsonSerializer.Serialize(resultContent.Result, ToolCallJsonSerializerOptions.GetTypeInfo(typeof(object))); |
597 | 603 | } |
598 | 604 | catch (NotSupportedException) |
599 | 605 | { |
@@ -622,7 +628,7 @@ private sealed class OpenAIChatToolJson |
622 | 628 | callRequest.Name, |
623 | 629 | new(JsonSerializer.SerializeToUtf8Bytes( |
624 | 630 | callRequest.Arguments, |
625 | | - JsonContext.GetTypeInfo(typeof(IDictionary<string, object?>), ToolCallJsonSerializerOptions))))); |
| 631 | + ToolCallJsonSerializerOptions.GetTypeInfo(typeof(IDictionary<string, object?>)))))); |
626 | 632 | } |
627 | 633 | } |
628 | 634 |
|
@@ -668,60 +674,19 @@ private static List<ChatMessageContentPart> GetContentParts(IList<AIContent> con |
668 | 674 |
|
669 | 675 | private static FunctionCallContent ParseCallContentFromJsonString(string json, string callId, string name) => |
670 | 676 | FunctionCallContent.CreateFromParsedArguments(json, callId, name, |
671 | | - argumentParser: static json => JsonSerializer.Deserialize(json, JsonContext.Default.IDictionaryStringObject)!); |
| 677 | + argumentParser: static json => JsonSerializer.Deserialize(json, |
| 678 | + (JsonTypeInfo<IDictionary<string, object>>)AIJsonUtilities.DefaultOptions.GetTypeInfo(typeof(IDictionary<string, object>)))!); |
672 | 679 |
|
673 | 680 | private static FunctionCallContent ParseCallContentFromBinaryData(BinaryData ut8Json, string callId, string name) => |
674 | 681 | FunctionCallContent.CreateFromParsedArguments(ut8Json, callId, name, |
675 | | - argumentParser: static json => JsonSerializer.Deserialize(json, JsonContext.Default.IDictionaryStringObject)!); |
| 682 | + argumentParser: static json => JsonSerializer.Deserialize(json, |
| 683 | + (JsonTypeInfo<IDictionary<string, object>>)AIJsonUtilities.DefaultOptions.GetTypeInfo(typeof(IDictionary<string, object>)))!); |
676 | 684 |
|
677 | 685 | /// <summary>Source-generated JSON type information.</summary> |
678 | 686 | [JsonSourceGenerationOptions(JsonSerializerDefaults.Web, |
679 | 687 | UseStringEnumConverter = true, |
680 | 688 | DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, |
681 | 689 | WriteIndented = true)] |
682 | 690 | [JsonSerializable(typeof(OpenAIChatToolJson))] |
683 | | - [JsonSerializable(typeof(IDictionary<string, object?>))] |
684 | | - [JsonSerializable(typeof(JsonElement))] |
685 | | - private sealed partial class JsonContext : JsonSerializerContext |
686 | | - { |
687 | | - /// <summary>Gets the <see cref="JsonSerializerOptions"/> singleton used as the default in JSON serialization operations.</summary> |
688 | | - private static readonly JsonSerializerOptions _defaultToolJsonOptions = CreateDefaultToolJsonOptions(); |
689 | | - |
690 | | - /// <summary>Gets JSON type information for the specified type.</summary> |
691 | | - /// <remarks> |
692 | | - /// This first tries to get the type information from <paramref name="firstOptions"/>, |
693 | | - /// falling back to <see cref="_defaultToolJsonOptions"/> if it can't. |
694 | | - /// </remarks> |
695 | | - public static JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions? firstOptions) => |
696 | | - firstOptions?.TryGetTypeInfo(type, out JsonTypeInfo? info) is true ? |
697 | | - info : |
698 | | - _defaultToolJsonOptions.GetTypeInfo(type); |
699 | | - |
700 | | - /// <summary>Creates the default <see cref="JsonSerializerOptions"/> to use for serialization-related operations.</summary> |
701 | | - [UnconditionalSuppressMessage("AotAnalysis", "IL3050", Justification = "DefaultJsonTypeInfoResolver is only used when reflection-based serialization is enabled")] |
702 | | - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026", Justification = "DefaultJsonTypeInfoResolver is only used when reflection-based serialization is enabled")] |
703 | | - private static JsonSerializerOptions CreateDefaultToolJsonOptions() |
704 | | - { |
705 | | - // If reflection-based serialization is enabled by default, use it, as it's the most permissive in terms of what it can serialize, |
706 | | - // and we want to be flexible in terms of what can be put into the various collections in the object model. |
707 | | - // Otherwise, use the source-generated options to enable trimming and Native AOT. |
708 | | - |
709 | | - if (JsonSerializer.IsReflectionEnabledByDefault) |
710 | | - { |
711 | | - // Keep in sync with the JsonSourceGenerationOptions attribute on JsonContext above. |
712 | | - JsonSerializerOptions options = new(JsonSerializerDefaults.Web) |
713 | | - { |
714 | | - TypeInfoResolver = new DefaultJsonTypeInfoResolver(), |
715 | | - Converters = { new JsonStringEnumConverter() }, |
716 | | - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, |
717 | | - WriteIndented = true, |
718 | | - }; |
719 | | - |
720 | | - options.MakeReadOnly(); |
721 | | - return options; |
722 | | - } |
723 | | - |
724 | | - return Default.Options; |
725 | | - } |
726 | | - } |
| 691 | + private sealed partial class JsonContext : JsonSerializerContext; |
727 | 692 | } |
0 commit comments