Skip to content

Commit ca23263

Browse files
authored
.Net: Update M.E.AI and OpenAI dependencies (#13095)
1 parent 5272beb commit ca23263

File tree

9 files changed

+44
-225
lines changed

9 files changed

+44
-225
lines changed

dotnet/Directory.Packages.props

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<PackageVersion Include="AWSSDK.SecurityToken" Version="4.0.1.6" />
2323
<PackageVersion Include="Azure.AI.Agents.Persistent" Version="1.0.0" />
2424
<PackageVersion Include="Azure.AI.ContentSafety" Version="1.0.0" />
25-
<PackageVersion Include="Azure.AI.OpenAI" Version="[2.3.0-beta.1]" />
25+
<PackageVersion Include="Azure.AI.OpenAI" Version="[2.3.0-beta.2]" />
2626
<PackageVersion Include="Azure.AI.Projects" Version="1.0.0-beta.9" />
2727
<PackageVersion Include="Azure.Identity" Version="1.14.2" />
2828
<PackageVersion Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.4.0" />
@@ -85,7 +85,7 @@
8585
<PackageVersion Include="Npgsql" Version="8.0.7" />
8686
<PackageVersion Include="OData2Linq" Version="2.2.0" />
8787
<PackageVersion Include="OllamaSharp" Version="5.3.5" />
88-
<PackageVersion Include="OpenAI" Version="[2.3.0]" />
88+
<PackageVersion Include="OpenAI" Version="[2.4.0]" />
8989
<PackageVersion Include="OpenTelemetry.Exporter.Console" Version="1.12.0" />
9090
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.12.0" />
9191
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
@@ -112,10 +112,10 @@
112112
<!-- Tokenizers -->
113113
<PackageVersion Include="Microsoft.ML.Tokenizers" Version="1.0.2" />
114114
<!-- Microsoft.Extensions.* -->
115-
<PackageVersion Include="Microsoft.Extensions.AI" Version="9.8.0" />
116-
<PackageVersion Include="Microsoft.Extensions.AI.Abstractions" Version="9.8.0" />
117-
<PackageVersion Include="Microsoft.Extensions.AI.AzureAIInference" Version="9.8.0-preview.1.25412.6" />
118-
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="9.8.0-preview.1.25412.6" />
115+
<PackageVersion Include="Microsoft.Extensions.AI" Version="9.9.0" />
116+
<PackageVersion Include="Microsoft.Extensions.AI.Abstractions" Version="9.9.0" />
117+
<PackageVersion Include="Microsoft.Extensions.AI.AzureAIInference" Version="9.9.0-preview.1.25458.4" />
118+
<PackageVersion Include="Microsoft.Extensions.AI.OpenAI" Version="9.9.0-preview.1.25458.4" />
119119
<PackageVersion Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
120120
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
121121
<PackageVersion Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.2" />

dotnet/samples/GettingStartedWithAgents/OpenAIAssistant/Step05_AssistantTool_FileSearch.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ await this.AssistantClient.CreateAssistantAsync(
3535
string vectorStoreId =
3636
await this.Client.CreateVectorStoreAsync(
3737
[fileId],
38-
waitUntilCompleted: true,
3938
metadata: SampleMetadata);
4039

4140
// Create a thread associated with a vector-store for the agent conversation.

dotnet/samples/GettingStartedWithAgents/OpenAIResponse/Step04_OpenAIResponseAgent_Tools.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

3+
using System.ClientModel;
34
using System.ClientModel.Primitives;
45
using Microsoft.SemanticKernel;
56
using Microsoft.SemanticKernel.Agents.OpenAI;
@@ -81,8 +82,7 @@ public async Task InvokeAgentWithFileSearchAsync()
8182
OpenAIFile file = await this.FileClient.UploadFileAsync(stream, filename: "employees.pdf", purpose: FileUploadPurpose.UserData);
8283

8384
// Create a vector store for the file
84-
CreateVectorStoreOperation createStoreOp = await this.VectorStoreClient.CreateVectorStoreAsync(
85-
waitUntilCompleted: true,
85+
ClientResult<VectorStore> createStoreOp = await this.VectorStoreClient.CreateVectorStoreAsync(
8686
new VectorStoreCreationOptions()
8787
{
8888
FileIds = { file.Id },
@@ -96,7 +96,7 @@ public async Task InvokeAgentWithFileSearchAsync()
9696

9797
// ResponseCreationOptions allows you to specify tools for the agent.
9898
ResponseCreationOptions creationOptions = new();
99-
creationOptions.Tools.Add(ResponseTool.CreateFileSearchTool([createStoreOp.VectorStoreId], null));
99+
creationOptions.Tools.Add(ResponseTool.CreateFileSearchTool([createStoreOp.Value.Id], null));
100100
OpenAIResponseAgentInvokeOptions invokeOptions = new()
101101
{
102102
ResponseCreationOptions = creationOptions,
@@ -124,7 +124,7 @@ public async Task InvokeAgentWithFileSearchAsync()
124124
// Clean up resources
125125
RequestOptions noThrowOptions = new() { ErrorOptions = ClientErrorBehaviors.NoThrow };
126126
this.FileClient.DeleteFile(file.Id, noThrowOptions);
127-
this.VectorStoreClient.DeleteVectorStore(createStoreOp.VectorStoreId, noThrowOptions);
127+
this.VectorStoreClient.DeleteVectorStore(createStoreOp.Value.Id, noThrowOptions);
128128
}
129129

130130
[Fact]

dotnet/src/Agents/OpenAI/Extensions/KernelFunctionExtensions.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,16 @@ public static ResponseTool ToResponseTool(this KernelFunction function, string?
5454
BinaryData parameterData = function.Metadata.CreateParameterSpec();
5555
return ResponseTool.CreateFunctionTool(
5656
functionName: FunctionName.ToFullyQualifiedName(function.Name, pluginName ?? function.PluginName),
57-
functionDescription: function.Description,
5857
functionParameters: parameterData,
59-
functionSchemaIsStrict: functionSchemaIsStrict);
58+
strictModeEnabled: functionSchemaIsStrict,
59+
functionDescription: function.Description);
6060
}
6161

6262
return ResponseTool.CreateFunctionTool(
6363
functionName: FunctionName.ToFullyQualifiedName(function.Name, pluginName ?? function.PluginName),
64-
functionDescription: function.Description,
65-
functionParameters: s_emptyFunctionParameters);
64+
functionParameters: s_emptyFunctionParameters,
65+
null,
66+
functionDescription: function.Description);
6667
}
6768

6869
#region private

dotnet/src/Agents/OpenAI/Extensions/OpenAIClientExtensions.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ public static class OpenAIClientExtensions
2020
/// </summary>
2121
/// <param name="client">The OpenAI client instance.</param>
2222
/// <param name="fileIds">The collection of file identifiers to include in the vector store.</param>
23-
/// <param name="waitUntilCompleted">Indicates whether to wait until the operation is completed.</param>
2423
/// <param name="storeName">The name of the vector store.</param>
2524
/// <param name="expirationPolicy">The expiration policy for the vector store.</param>
2625
/// <param name="chunkingStrategy">The chunking strategy for the vector store.</param>
@@ -30,7 +29,6 @@ public static class OpenAIClientExtensions
3029
public static async Task<string> CreateVectorStoreAsync(
3130
this OpenAIClient client,
3231
IEnumerable<string> fileIds,
33-
bool waitUntilCompleted = true,
3432
string? storeName = null,
3533
VectorStoreExpirationPolicy? expirationPolicy = null,
3634
FileChunkingStrategy? chunkingStrategy = null,
@@ -55,9 +53,9 @@ public static async Task<string> CreateVectorStoreAsync(
5553
}
5654

5755
VectorStoreClient vectorStoreClient = client.GetVectorStoreClient();
58-
CreateVectorStoreOperation result = await vectorStoreClient.CreateVectorStoreAsync(waitUntilCompleted, options, cancellationToken).ConfigureAwait(false);
56+
var result = await vectorStoreClient.CreateVectorStoreAsync(options, cancellationToken).ConfigureAwait(false);
5957

60-
return result.VectorStoreId;
58+
return result.Value.Id;
6159
}
6260

6361
/// <summary>

dotnet/src/Agents/OpenAI/Extensions/OpenAIResponseExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ private static ChatMessageContentItemCollection ToChatMessageContentItemCollecti
195195
return collection;
196196
}
197197

198-
private static ChatMessageContentItemCollection ToChatMessageContentItemCollection(this IReadOnlyList<ReasoningSummaryPart> parts)
198+
private static ChatMessageContentItemCollection ToChatMessageContentItemCollection(this IList<ReasoningSummaryPart> parts)
199199
{
200200
var collection = new ChatMessageContentItemCollection();
201201
foreach (var part in parts)

dotnet/src/Agents/OpenAI/Internal/ResponseCreationOptionsFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ internal static ResponseCreationOptions CreateOptions(
2626
EndUserId = responseAgentInvokeOptions.ResponseCreationOptions.EndUserId ?? agent.GetDisplayName(),
2727
Instructions = responseAgentInvokeOptions.ResponseCreationOptions.Instructions ?? instructions,
2828
StoredOutputEnabled = responseAgentInvokeOptions.ResponseCreationOptions.StoredOutputEnabled ?? agent.StoreEnabled,
29-
Background = responseAgentInvokeOptions.ResponseCreationOptions.Background,
29+
BackgroundModeEnabled = responseAgentInvokeOptions.ResponseCreationOptions.BackgroundModeEnabled,
3030
ReasoningOptions = responseAgentInvokeOptions.ResponseCreationOptions.ReasoningOptions,
3131
MaxOutputTokenCount = responseAgentInvokeOptions.ResponseCreationOptions.MaxOutputTokenCount,
3232
TextOptions = responseAgentInvokeOptions.ResponseCreationOptions.TextOptions,

dotnet/src/Agents/UnitTests/OpenAI/Extensions/OpenAIClientExtensionsTests.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public async Task VerifyCreateDefaultVectorStoreAsync()
3434
this.SetupResponse(HttpStatusCode.OK, OpenAIAssistantResponseContent.CreateVectorStore);
3535

3636
// Act
37-
string storeId = await this._client.CreateVectorStoreAsync(fileIds, waitUntilCompleted: false);
37+
string storeId = await this._client.CreateVectorStoreAsync(fileIds);
3838

3939
// Assert
4040
Assert.NotNull(storeId);
@@ -59,7 +59,6 @@ public async Task VerifyCreateVectorStoreAsync()
5959
// Act
6060
string storeId = await this._client.CreateVectorStoreAsync(
6161
fileIds,
62-
waitUntilCompleted: false,
6362
storeName: "test-store",
6463
expirationPolicy: new VectorStoreExpirationPolicy(VectorStoreExpirationAnchor.LastActiveAt, 30),
6564
chunkingStrategy: FileChunkingStrategy.Auto,

dotnet/src/Agents/UnitTests/OpenAI/Extensions/OpenAIResponseExtensionsTests.cs

Lines changed: 24 additions & 202 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
using System;
44
using System.Collections.Generic;
5-
using System.Linq;
6-
using System.Reflection;
75
using Microsoft.SemanticKernel;
86
using Microsoft.SemanticKernel.Agents.OpenAI;
97
using Microsoft.SemanticKernel.ChatCompletion;
@@ -233,206 +231,30 @@ public void VerifyToChatMessageContentWithMixedResponseItems()
233231
}
234232

235233
#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);
436258

437259
#endregion
438260
}

0 commit comments

Comments
 (0)