|
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