77using System . Runtime . CompilerServices ;
88using System . Text ;
99using System . Text . Json ;
10- using System . Text . Json . Serialization ;
1110using System . Threading ;
1211using System . Threading . Tasks ;
1312using Microsoft . Shared . Diagnostics ;
2322namespace Microsoft . Extensions . AI ;
2423
2524/// <summary>Represents an <see cref="IChatClient"/> for an OpenAI <see cref="OpenAIClient"/> or <see cref="ChatClient"/>.</summary>
26- internal sealed partial class OpenAIChatClient : IChatClient
25+ internal sealed class OpenAIChatClient : IChatClient
2726{
2827 /// <summary>Metadata about the client.</summary>
2928 private readonly ChatClientMetadata _metadata ;
@@ -104,18 +103,9 @@ void IDisposable.Dispose()
104103 /// <summary>Converts an Extensions function to an OpenAI chat tool.</summary>
105104 internal static ChatTool ToOpenAIChatTool ( AIFunction aiFunction )
106105 {
107- bool ? strict =
108- aiFunction . AdditionalProperties . TryGetValue ( OpenAIClientExtensions . StrictKey , out object ? strictObj ) &&
109- strictObj is bool strictValue ?
110- strictValue : null ;
111-
112- // Perform transformations making the schema legal per OpenAI restrictions
113- JsonElement jsonSchema = OpenAIClientExtensions . GetSchema ( aiFunction , strict ) ;
114-
115- // Map to an intermediate model so that redundant properties are skipped.
116- var tool = JsonSerializer . Deserialize ( jsonSchema , ChatClientJsonContext . Default . ChatToolJson ) ! ;
117- var functionParameters = BinaryData . FromBytes ( JsonSerializer . SerializeToUtf8Bytes ( tool , ChatClientJsonContext . Default . ChatToolJson ) ) ;
118- return ChatTool . CreateFunctionTool ( aiFunction . Name , aiFunction . Description , functionParameters , strict ) ;
106+ ( BinaryData parameters , bool ? strict ) = OpenAIClientExtensions . ToOpenAIFunctionParameters ( aiFunction ) ;
107+
108+ return ChatTool . CreateFunctionTool ( aiFunction . Name , aiFunction . Description , parameters , strict ) ;
119109 }
120110
121111 /// <summary>Converts an Extensions chat message enumerable to an OpenAI chat message enumerable.</summary>
@@ -564,8 +554,7 @@ private ChatCompletionOptions ToOpenAIOptions(ChatOptions? options)
564554 result . ResponseFormat = OpenAIClientExtensions . StrictSchemaTransformCache . GetOrCreateTransformedSchema ( jsonFormat ) is { } jsonSchema ?
565555 OpenAI . Chat . ChatResponseFormat . CreateJsonSchemaFormat (
566556 jsonFormat . SchemaName ?? "json_schema" ,
567- BinaryData . FromBytes (
568- JsonSerializer . SerializeToUtf8Bytes ( jsonSchema , ChatClientJsonContext . Default . JsonElement ) ) ,
557+ BinaryData . FromBytes ( JsonSerializer . SerializeToUtf8Bytes ( jsonSchema , OpenAIJsonContext . Default . JsonElement ) ) ,
569558 jsonFormat . SchemaDescription ) :
570559 OpenAI . Chat . ChatResponseFormat . CreateJsonObjectFormat ( ) ;
571560 }
@@ -668,27 +657,11 @@ private static ChatRole FromOpenAIChatRole(ChatMessageRole role) =>
668657
669658 private static FunctionCallContent ParseCallContentFromJsonString ( string json , string callId , string name ) =>
670659 FunctionCallContent . CreateFromParsedArguments ( json , callId , name ,
671- argumentParser : static json => JsonSerializer . Deserialize ( json , ChatClientJsonContext . Default . IDictionaryStringObject ) ! ) ;
660+ argumentParser : static json => JsonSerializer . Deserialize ( json , OpenAIJsonContext . Default . IDictionaryStringObject ) ! ) ;
672661
673662 private static FunctionCallContent ParseCallContentFromBinaryData ( BinaryData ut8Json , string callId , string name ) =>
674663 FunctionCallContent . CreateFromParsedArguments ( ut8Json , callId , name ,
675- argumentParser : static json => JsonSerializer . Deserialize ( json , ChatClientJsonContext . Default . IDictionaryStringObject ) ! ) ;
676-
677- /// <summary>Used to create the JSON payload for an OpenAI chat tool description.</summary>
678- private sealed class ChatToolJson
679- {
680- [ JsonPropertyName ( "type" ) ]
681- public string Type { get ; set ; } = "object" ;
682-
683- [ JsonPropertyName ( "required" ) ]
684- public HashSet < string > Required { get ; set ; } = [ ] ;
685-
686- [ JsonPropertyName ( "properties" ) ]
687- public Dictionary < string , JsonElement > Properties { get ; set ; } = [ ] ;
688-
689- [ JsonPropertyName ( "additionalProperties" ) ]
690- public bool AdditionalProperties { get ; set ; }
691- }
664+ argumentParser : static json => JsonSerializer . Deserialize ( json , OpenAIJsonContext . Default . IDictionaryStringObject ) ! ) ;
692665
693666 /// <summary>POCO representing function calling info. Used to concatenation information for a single function call from across multiple streaming updates.</summary>
694667 private sealed class FunctionCallInfo
@@ -697,14 +670,4 @@ private sealed class FunctionCallInfo
697670 public string ? Name ;
698671 public StringBuilder ? Arguments ;
699672 }
700-
701- /// <summary>Source-generated JSON type information.</summary>
702- [ JsonSourceGenerationOptions ( JsonSerializerDefaults . Web ,
703- UseStringEnumConverter = true ,
704- DefaultIgnoreCondition = JsonIgnoreCondition . WhenWritingNull ,
705- WriteIndented = true ) ]
706- [ JsonSerializable ( typeof ( ChatToolJson ) ) ]
707- [ JsonSerializable ( typeof ( IDictionary < string , object ? > ) ) ]
708- [ JsonSerializable ( typeof ( string [ ] ) ) ]
709- private sealed partial class ChatClientJsonContext : JsonSerializerContext ;
710673}
0 commit comments