|
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