6
6
using System . ComponentModel ;
7
7
using System . Linq ;
8
8
using System . Text . Json ;
9
+ using System . Threading . Tasks ;
9
10
using OpenAI . Assistants ;
10
11
using OpenAI . Chat ;
11
12
using OpenAI . Realtime ;
@@ -77,8 +78,10 @@ private static void ValidateSchemaParameters(BinaryData parameters)
77
78
Assert . Equal ( "The name parameter" , nameProperty . GetProperty ( "description" ) . GetString ( ) ) ;
78
79
}
79
80
80
- [ Fact ]
81
- public void AsOpenAIChatMessages_ProducesExpectedOutput ( )
81
+ [ Theory ]
82
+ [ InlineData ( false ) ]
83
+ [ InlineData ( true ) ]
84
+ public void AsOpenAIChatMessages_ProducesExpectedOutput ( bool withOptions )
82
85
{
83
86
Assert . Throws < ArgumentNullException > ( "messages" , ( ) => ( ( IEnumerable < ChatMessage > ) null ! ) . AsOpenAIChatMessages ( ) ) ;
84
87
@@ -99,17 +102,31 @@ public void AsOpenAIChatMessages_ProducesExpectedOutput()
99
102
new ( ChatRole . Assistant , "The answer is 42." ) ,
100
103
] ;
101
104
102
- var convertedMessages = messages . AsOpenAIChatMessages ( ) . ToArray ( ) ;
105
+ ChatOptions ? options = withOptions ? new ChatOptions { Instructions = "You talk like a parrot." } : null ;
106
+
107
+ var convertedMessages = messages . AsOpenAIChatMessages ( options ) . ToArray ( ) ;
103
108
104
- Assert . Equal ( 5 , convertedMessages . Length ) ;
109
+ int index = 0 ;
110
+ if ( withOptions )
111
+ {
112
+ Assert . Equal ( 6 , convertedMessages . Length ) ;
113
+
114
+ index = 1 ;
115
+ SystemChatMessage instructionsMessage = Assert . IsType < SystemChatMessage > ( convertedMessages [ 0 ] ) ;
116
+ Assert . Equal ( "You talk like a parrot." , Assert . Single ( instructionsMessage . Content ) . Text ) ;
117
+ }
118
+ else
119
+ {
120
+ Assert . Equal ( 5 , convertedMessages . Length ) ;
121
+ }
105
122
106
- SystemChatMessage m0 = Assert . IsType < SystemChatMessage > ( convertedMessages [ 0 ] ) ;
123
+ SystemChatMessage m0 = Assert . IsType < SystemChatMessage > ( convertedMessages [ index ] ) ;
107
124
Assert . Equal ( "You are a helpful assistant." , Assert . Single ( m0 . Content ) . Text ) ;
108
125
109
- UserChatMessage m1 = Assert . IsType < UserChatMessage > ( convertedMessages [ 1 ] ) ;
126
+ UserChatMessage m1 = Assert . IsType < UserChatMessage > ( convertedMessages [ index + 1 ] ) ;
110
127
Assert . Equal ( "Hello" , Assert . Single ( m1 . Content ) . Text ) ;
111
128
112
- AssistantChatMessage m2 = Assert . IsType < AssistantChatMessage > ( convertedMessages [ 2 ] ) ;
129
+ AssistantChatMessage m2 = Assert . IsType < AssistantChatMessage > ( convertedMessages [ index + 2 ] ) ;
113
130
Assert . Single ( m2 . Content ) ;
114
131
Assert . Equal ( "Hi there!" , m2 . Content [ 0 ] . Text ) ;
115
132
var tc = Assert . Single ( m2 . ToolCalls ) ;
@@ -121,11 +138,11 @@ public void AsOpenAIChatMessages_ProducesExpectedOutput()
121
138
[ "param2" ] = 42
122
139
} ) , JsonSerializer . Deserialize < JsonElement > ( tc . FunctionArguments . ToMemory ( ) . Span ) ) ) ;
123
140
124
- ToolChatMessage m3 = Assert . IsType < ToolChatMessage > ( convertedMessages [ 3 ] ) ;
141
+ ToolChatMessage m3 = Assert . IsType < ToolChatMessage > ( convertedMessages [ index + 3 ] ) ;
125
142
Assert . Equal ( "callid123" , m3 . ToolCallId ) ;
126
143
Assert . Equal ( "theresult" , Assert . Single ( m3 . Content ) . Text ) ;
127
144
128
- AssistantChatMessage m4 = Assert . IsType < AssistantChatMessage > ( convertedMessages [ 4 ] ) ;
145
+ AssistantChatMessage m4 = Assert . IsType < AssistantChatMessage > ( convertedMessages [ index + 4 ] ) ;
129
146
Assert . Equal ( "The answer is 42." , Assert . Single ( m4 . Content ) . Text ) ;
130
147
}
131
148
@@ -216,4 +233,69 @@ public void AsChatResponse_ConvertsOpenAIChatCompletion()
216
233
Assert . Equal ( "http://example.com/image.png" , Assert . IsType < UriContent > ( message . Contents [ 1 ] ) . Uri . ToString ( ) ) ;
217
234
Assert . Equal ( "functionName" , Assert . IsType < FunctionCallContent > ( message . Contents [ 2 ] ) . Name ) ;
218
235
}
236
+
237
+ [ Fact ]
238
+ public async Task AsChatResponse_ConvertsOpenAIStreamingChatCompletionUpdates ( )
239
+ {
240
+ Assert . Throws < ArgumentNullException > ( "chatCompletionUpdates" , ( ) => ( ( IAsyncEnumerable < StreamingChatCompletionUpdate > ) null ! ) . AsChatResponseUpdatesAsync ( ) ) ;
241
+
242
+ List < ChatResponseUpdate > updates = [ ] ;
243
+ await foreach ( var update in CreateUpdates ( ) . AsChatResponseUpdatesAsync ( ) )
244
+ {
245
+ updates . Add ( update ) ;
246
+ }
247
+
248
+ ChatResponse response = updates . ToChatResponse ( ) ;
249
+
250
+ Assert . Equal ( "id" , response . ResponseId ) ;
251
+ Assert . Equal ( ChatFinishReason . ToolCalls , response . FinishReason ) ;
252
+ Assert . Equal ( "model123" , response . ModelId ) ;
253
+ Assert . Equal ( new DateTimeOffset ( 2025 , 1 , 1 , 0 , 0 , 0 , TimeSpan . Zero ) , response . CreatedAt ) ;
254
+ Assert . NotNull ( response . Usage ) ;
255
+ Assert . Equal ( 1 , response . Usage . InputTokenCount ) ;
256
+ Assert . Equal ( 2 , response . Usage . OutputTokenCount ) ;
257
+ Assert . Equal ( 3 , response . Usage . TotalTokenCount ) ;
258
+
259
+ ChatMessage message = Assert . Single ( response . Messages ) ;
260
+ Assert . Equal ( ChatRole . Assistant , message . Role ) ;
261
+
262
+ Assert . Equal ( 3 , message . Contents . Count ) ;
263
+ Assert . Equal ( "Hello, world!" , Assert . IsType < TextContent > ( message . Contents [ 0 ] ) . Text ) ;
264
+ Assert . Equal ( "http://example.com/image.png" , Assert . IsType < UriContent > ( message . Contents [ 1 ] ) . Uri . ToString ( ) ) ;
265
+ Assert . Equal ( "functionName" , Assert . IsType < FunctionCallContent > ( message . Contents [ 2 ] ) . Name ) ;
266
+
267
+ static async IAsyncEnumerable < StreamingChatCompletionUpdate > CreateUpdates ( )
268
+ {
269
+ await Task . Yield ( ) ;
270
+ yield return OpenAIChatModelFactory . StreamingChatCompletionUpdate (
271
+ "id" ,
272
+ new ChatMessageContent (
273
+ ChatMessageContentPart . CreateTextPart ( "Hello, world!" ) ,
274
+ ChatMessageContentPart . CreateImagePart ( new Uri ( "http://example.com/image.png" ) ) ) ,
275
+ null ,
276
+ [ OpenAIChatModelFactory . StreamingChatToolCallUpdate ( 0 , "id" , ChatToolCallKind . Function , "functionName" , BinaryData . FromString ( "test" ) ) ] ,
277
+ ChatMessageRole . Assistant ,
278
+ null , null , null , OpenAI . Chat . ChatFinishReason . ToolCalls , new DateTimeOffset ( 2025 , 1 , 1 , 0 , 0 , 0 , TimeSpan . Zero ) ,
279
+ "model123" , null , OpenAIChatModelFactory . ChatTokenUsage ( 2 , 1 , 3 ) ) ;
280
+ }
281
+ }
282
+
283
+ [ Fact ]
284
+ public void AsChatResponse_ConvertsOpenAIResponse ( )
285
+ {
286
+ Assert . Throws < ArgumentNullException > ( "response" , ( ) => ( ( OpenAIResponse ) null ! ) . AsChatResponse ( ) ) ;
287
+
288
+ // The OpenAI library currently doesn't provide any way to create an OpenAIResponse instance,
289
+ // as all constructors/factory methods currently are internal. Update this test when such functionality is available.
290
+ }
291
+
292
+ [ Fact ]
293
+ public void AsChatResponseUpdatesAsync_ConvertsOpenAIStreamingResponseUpdates ( )
294
+ {
295
+ Assert . Throws < ArgumentNullException > ( "responseUpdates" , ( ) => ( ( IAsyncEnumerable < StreamingResponseUpdate > ) null ! ) . AsChatResponseUpdatesAsync ( ) ) ;
296
+
297
+ // The OpenAI library currently doesn't provide any way to create a StreamingResponseUpdate instance,
298
+ // as all constructors/factory methods currently are internal. Update this test when such functionality is available.
299
+ }
300
+
219
301
}
0 commit comments