|
2 | 2 |
|
3 | 3 | using System; |
4 | 4 | using System.Collections.Generic; |
5 | | -using System.Linq; |
6 | | -using System.Reflection; |
7 | 5 | using Microsoft.SemanticKernel; |
8 | 6 | using Microsoft.SemanticKernel.Agents.OpenAI; |
9 | 7 | using Microsoft.SemanticKernel.ChatCompletion; |
@@ -233,206 +231,30 @@ public void VerifyToChatMessageContentWithMixedResponseItems() |
233 | 231 | } |
234 | 232 |
|
235 | 233 | #region private |
236 | | - private OpenAIResponse CreateMockOpenAIResponse(string model, IEnumerable<ResponseItem> outputItems) |
237 | | - { |
238 | | -#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. |
239 | | - return this.CreateMockOpenAIResponse( |
240 | | - "id", |
241 | | - DateTimeOffset.Now, |
242 | | - null, |
243 | | - "instructions", |
244 | | - model, |
245 | | - "previousResponseId", |
246 | | - 0, |
247 | | - [], |
248 | | - 0, |
249 | | - null, |
250 | | - null, |
251 | | - outputItems, |
252 | | - false, |
253 | | - ResponseToolChoice.CreateAutoChoice()); |
254 | | -#pragma warning restore CS8625 // Cannot convert null literal to non-nullable reference type. |
255 | | - } |
256 | | - private OpenAIResponse CreateMockOpenAIResponse(string id, DateTimeOffset createdAt, ResponseError error, string instructions, string model, string previousResponseId, float temperature, IEnumerable<ResponseTool> tools, float topP, IDictionary<string, string> metadata, ResponseIncompleteStatusDetails incompleteStatusDetails, IEnumerable<ResponseItem> outputItems, bool parallelToolCallsEnabled, ResponseToolChoice toolChoice) |
257 | | - { |
258 | | - Type type = typeof(OpenAIResponse); |
259 | | - var assembly = type.Assembly; |
260 | | - var internalServiceTierType = assembly.GetType("OpenAI.Internal.InternalServiceTier"); |
261 | | - var nullableInternalServiceTierType = typeof(Nullable<>).MakeGenericType(internalServiceTierType!); |
262 | | - |
263 | | - ConstructorInfo? constructor = type.GetConstructor( |
264 | | - BindingFlags.Instance | BindingFlags.NonPublic, |
265 | | - null, |
266 | | - [ |
267 | | - typeof(IDictionary<string, string>), |
268 | | - typeof(float?), |
269 | | - typeof(float?), |
270 | | - nullableInternalServiceTierType, |
271 | | - typeof(string), |
272 | | - typeof(bool?), |
273 | | - typeof(string), |
274 | | - typeof(IList<ResponseTool>), |
275 | | - typeof(string), |
276 | | - typeof(ResponseStatus?), |
277 | | - typeof(DateTimeOffset), |
278 | | - typeof(ResponseError), |
279 | | - typeof(ResponseTokenUsage), |
280 | | - typeof(string), |
281 | | - typeof(ResponseReasoningOptions), |
282 | | - typeof(int?), |
283 | | - typeof(ResponseTextOptions), |
284 | | - typeof(ResponseTruncationMode?), |
285 | | - typeof(ResponseIncompleteStatusDetails), |
286 | | - typeof(IList<ResponseItem>), |
287 | | - typeof(bool), |
288 | | - typeof(ResponseToolChoice), |
289 | | - typeof(string), |
290 | | - typeof(string), |
291 | | - typeof(IDictionary<string, BinaryData>) |
292 | | - ], |
293 | | - null); |
294 | | - |
295 | | - if (constructor != null) |
296 | | - { |
297 | | - return (OpenAIResponse)constructor.Invoke( |
298 | | - [ |
299 | | - metadata, |
300 | | - (float?)temperature, |
301 | | - (float?)topP, |
302 | | - null, // serviceTier |
303 | | - previousResponseId, |
304 | | - null, // background |
305 | | - instructions, |
306 | | - tools.ToList(), |
307 | | - id, |
308 | | - null, // status |
309 | | - createdAt, |
310 | | - error, |
311 | | - null, // usage |
312 | | - null, // endUserId |
313 | | - null, // reasoningOptions |
314 | | - null, // maxOutputTokenCount |
315 | | - null, // textOptions |
316 | | - null, // truncationMode |
317 | | - incompleteStatusDetails, |
318 | | - outputItems.ToList(), |
319 | | - parallelToolCallsEnabled, |
320 | | - toolChoice, |
321 | | - model, |
322 | | - "response", |
323 | | - null // additionalBinaryDataProperties |
324 | | - ] |
325 | | - ); |
326 | | - } |
327 | | - throw new InvalidOperationException("Constructor not found."); |
328 | | - } |
329 | | - |
330 | | - private ReasoningResponseItem CreateReasoningResponseItem(string? reasoningText = null, IReadOnlyList<ReasoningSummaryPart>? summaryParts = null) |
331 | | - { |
332 | | - Type reasoningResponseItemType = typeof(ReasoningResponseItem); |
333 | | - Type reasoningSummaryTextPartType = typeof(ReasoningSummaryTextPart); |
334 | | - |
335 | | - // If reasoningText is provided and summaryParts is not, create summaryParts with the text |
336 | | - if (reasoningText != null && summaryParts == null) |
337 | | - { |
338 | | - // Try to find any public static factory method or constructor that can create ReasoningSummaryTextPart |
339 | | - var createTextPartMethod = typeof(ReasoningSummaryPart).GetMethod( |
340 | | - "CreateTextPart", |
341 | | - BindingFlags.Static | BindingFlags.Public, |
342 | | - null, |
343 | | - [typeof(string)], |
344 | | - null); |
345 | | - |
346 | | - if (createTextPartMethod != null) |
347 | | - { |
348 | | - var textPart = createTextPartMethod.Invoke(null, [reasoningText]) as ReasoningSummaryTextPart; |
349 | | - summaryParts = textPart != null ? new List<ReasoningSummaryPart> { textPart } : new List<ReasoningSummaryPart>(); |
350 | | - } |
351 | | - else |
352 | | - { |
353 | | - // Try to find constructor - search for all constructors |
354 | | - var textPartConstructors = reasoningSummaryTextPartType.GetConstructors( |
355 | | - BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); |
356 | | - |
357 | | - ConstructorInfo? textPartConstructor = null; |
358 | | - foreach (var ctor in textPartConstructors) |
359 | | - { |
360 | | - var parameters = ctor.GetParameters(); |
361 | | - if (parameters.Length >= 1 && parameters[0].ParameterType == typeof(string)) |
362 | | - { |
363 | | - textPartConstructor = ctor; |
364 | | - break; |
365 | | - } |
366 | | - } |
367 | | - |
368 | | - if (textPartConstructor != null) |
369 | | - { |
370 | | - var ctorParams = textPartConstructor.GetParameters(); |
371 | | - var args = new object?[ctorParams.Length]; |
372 | | - args[0] = reasoningText; |
373 | | - // Fill in any additional parameters with null or default values |
374 | | - for (int i = 1; i < ctorParams.Length; i++) |
375 | | - { |
376 | | - args[i] = null; |
377 | | - } |
378 | | - |
379 | | - var textPart = textPartConstructor.Invoke(args) as ReasoningSummaryTextPart; |
380 | | - summaryParts = textPart != null ? new List<ReasoningSummaryPart> { textPart } : new List<ReasoningSummaryPart>(); |
381 | | - } |
382 | | - else |
383 | | - { |
384 | | - throw new InvalidOperationException("Could not find a way to create ReasoningSummaryTextPart."); |
385 | | - } |
386 | | - } |
387 | | - } |
388 | | - |
389 | | - // Convert null summaryParts to empty list for method calls |
390 | | - var partsToPass = summaryParts ?? new List<ReasoningSummaryPart>(); |
391 | | - |
392 | | - // Try to find a static factory method first |
393 | | - var createReasoningItemMethod = typeof(ResponseItem).GetMethod( |
394 | | - "CreateReasoningItem", |
395 | | - BindingFlags.Static | BindingFlags.Public, |
396 | | - null, |
397 | | - [typeof(IEnumerable<ReasoningSummaryPart>)], |
398 | | - null); |
399 | | - |
400 | | - if (createReasoningItemMethod != null) |
401 | | - { |
402 | | - return (ReasoningResponseItem)createReasoningItemMethod.Invoke(null, [partsToPass])!; |
403 | | - } |
404 | | - |
405 | | - // If no factory method, look for constructors |
406 | | - var constructors = reasoningResponseItemType.GetConstructors( |
407 | | - BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); |
408 | | - |
409 | | - foreach (var ctor in constructors) |
410 | | - { |
411 | | - var parameters = ctor.GetParameters(); |
412 | | - |
413 | | - // Look for constructor that takes IReadOnlyList<ReasoningSummaryPart> or similar |
414 | | - if (parameters.Length >= 1) |
415 | | - { |
416 | | - var firstParamType = parameters[0].ParameterType; |
417 | | - if (firstParamType.IsAssignableFrom(typeof(List<ReasoningSummaryPart>)) || |
418 | | - firstParamType.IsAssignableFrom(typeof(IReadOnlyList<ReasoningSummaryPart>)) || |
419 | | - firstParamType.IsAssignableFrom(typeof(IEnumerable<ReasoningSummaryPart>))) |
420 | | - { |
421 | | - var args = new object?[parameters.Length]; |
422 | | - args[0] = partsToPass; |
423 | | - // Fill in any additional parameters with null |
424 | | - for (int i = 1; i < parameters.Length; i++) |
425 | | - { |
426 | | - args[i] = null; |
427 | | - } |
428 | | - |
429 | | - return (ReasoningResponseItem)ctor.Invoke(args); |
430 | | - } |
431 | | - } |
432 | | - } |
433 | | - |
434 | | - throw new InvalidOperationException("Constructor not found for ReasoningResponseItem."); |
435 | | - } |
| 234 | + private OpenAIResponse CreateMockOpenAIResponse(string model, IEnumerable<ResponseItem> outputItems) => |
| 235 | + OpenAIResponsesModelFactory.OpenAIResponse( |
| 236 | + model: model, |
| 237 | + outputItems: outputItems); |
| 238 | + |
| 239 | + private OpenAIResponse CreateMockOpenAIResponse(string id, DateTimeOffset createdAt, ResponseError error, string instructions, string model, string previousResponseId, float temperature, IEnumerable<ResponseTool> tools, float topP, IDictionary<string, string> metadata, ResponseIncompleteStatusDetails incompleteStatusDetails, IEnumerable<ResponseItem> outputItems, bool parallelToolCallsEnabled, ResponseToolChoice toolChoice) => |
| 240 | + OpenAIResponsesModelFactory.OpenAIResponse( |
| 241 | + id: id, |
| 242 | + createdAt: createdAt, |
| 243 | + error: error, |
| 244 | + instructions: instructions, |
| 245 | + model: model, |
| 246 | + previousResponseId: previousResponseId, |
| 247 | + temperature: temperature, |
| 248 | + tools: tools, |
| 249 | + topP: topP, |
| 250 | + metadata: metadata, |
| 251 | + incompleteStatusDetails: incompleteStatusDetails, |
| 252 | + outputItems: outputItems, |
| 253 | + parallelToolCallsEnabled: parallelToolCallsEnabled, |
| 254 | + toolChoice: toolChoice); |
| 255 | + |
| 256 | + private ReasoningResponseItem CreateReasoningResponseItem(string? reasoningText = null) => |
| 257 | + OpenAIResponsesModelFactory.ReasoningResponseItem(summaryText: reasoningText); |
436 | 258 |
|
437 | 259 | #endregion |
438 | 260 | } |
0 commit comments