Skip to content

Commit 8f10b71

Browse files
trrwilsonCopilot
andauthored
Azure.AI.OpenAI: 2.7.0-beta.1 for OpenAI 2.7.0 compat (#54126)
* restore 2.7.0 compat to AOAI library * export-api updates (for unavailable client overrides) * Update sdk/openai/Azure.AI.OpenAI/tests/ChatTests.cs Co-authored-by: Copilot <[email protected]> * Update sdk/openai/Azure.AI.OpenAI/CHANGELOG.md Co-authored-by: Copilot <[email protected]> * Update sdk/openai/Azure.AI.OpenAI/src/Custom/Chat/AzureChatExtensions.cs Co-authored-by: Copilot <[email protected]> * Update sdk/openai/Azure.AI.OpenAI/src/Custom/VectorStores/VectorStoreCollectionPageToken.cs Co-authored-by: Copilot <[email protected]> * name alignment suggestions * Copilot PR feedback --------- Co-authored-by: Copilot <[email protected]>
1 parent 96e4574 commit 8f10b71

16 files changed

+795
-219
lines changed

eng/Packages.Data.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@
213213
</ItemGroup>
214214

215215
<ItemGroup Condition="$(MSBuildProjectName.StartsWith('Azure.AI.OpenAI'))">
216-
<PackageReference Update="OpenAI" Version="2.5.0" />
216+
<PackageReference Update="OpenAI" Version="2.7.0" />
217217
</ItemGroup>
218218

219219
<ItemGroup Condition="$(MSBuildProjectName.StartsWith('Azure.Developer.Playwright'))">

sdk/openai/Azure.AI.OpenAI/CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Release History
22

3+
## 2.7.0-beta.1 (2025-11-24)
4+
5+
This update restores compatibility with the latest `2.7.0` release of `OpenAI` and enables access to the latest features. For details, please see [the full OpenAI 2.7.0 release notes](https://github.com/openai/openai-dotnet/blob/main/CHANGELOG.md#270-2025-11-13).
6+
7+
### Features Added
8+
9+
- A substantial number of new features are carried forward from the `OpenAI` library. Please see [the full OpenAI 2.5.0 release notes](https://github.com/openai/openai-dotnet/blob/main/CHANGELOG.md#270-2025-11-13) for details.
10+
11+
### Breaking Changes
12+
13+
**`[Experimental]` Chat Extensions**
14+
15+
- Explicitly assigning `null` to the `MaxOutputTokens` property of a `ChatCompletionOptions` instance will now reset opt-in to
16+
contemporary serialization of `max_output_tokens` via `.SetNewMaxOutputTokensPropertyEnabled()`. Please ensure the extension
17+
method is invoked after non-null assignment of `MaxOutputTokens`.
18+
319
## 2.5.0-beta.1 (2025-10-03)
420

521
This update restores compatibility with the latest `2.5.0` release of `OpenAI` and enables access to the latest features. For details, please see [the full OpenAI 2.5.0 release notes](https://github.com/openai/openai-dotnet/blob/main/CHANGELOG.md#250-2025-09-23).

sdk/openai/Azure.AI.OpenAI/api/Azure.AI.OpenAI.net8.0.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,17 @@ public AzureOpenAIClient(System.Uri endpoint, System.ClientModel.ApiKeyCredentia
106106
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("OPENAI001")]
107107
public override OpenAI.Batch.BatchClient GetBatchClient() { throw null; }
108108
public override OpenAI.Chat.ChatClient GetChatClient(string deploymentName) { throw null; }
109+
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
110+
public override OpenAI.Containers.ContainerClient GetContainerClient() { throw null; }
111+
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
112+
public override OpenAI.Conversations.ConversationClient GetConversationClient() { throw null; }
109113
public override OpenAI.Embeddings.EmbeddingClient GetEmbeddingClient(string deploymentName) { throw null; }
110114
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("OPENAI001")]
111115
public override OpenAI.Evals.EvaluationClient GetEvaluationClient() { throw null; }
112116
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("OPENAI001")]
113117
public override OpenAI.FineTuning.FineTuningClient GetFineTuningClient() { throw null; }
118+
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
119+
public override OpenAI.Graders.GraderClient GetGraderClient() { throw null; }
114120
public override OpenAI.Images.ImageClient GetImageClient(string deploymentName) { throw null; }
115121
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
116122
public override OpenAI.Moderations.ModerationClient GetModerationClient(string _) { throw null; }
@@ -123,6 +129,8 @@ public AzureOpenAIClient(System.Uri endpoint, System.ClientModel.ApiKeyCredentia
123129
public override OpenAI.Realtime.RealtimeClient GetRealtimeClient() { throw null; }
124130
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("OPENAI001")]
125131
public override OpenAI.VectorStores.VectorStoreClient GetVectorStoreClient() { throw null; }
132+
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
133+
public override OpenAI.Videos.VideoClient GetVideoClient() { throw null; }
126134
}
127135
public partial class AzureOpenAIClientOptions : System.ClientModel.Primitives.ClientPipelineOptions
128136
{
@@ -426,8 +434,6 @@ public static void AddDataSource(this OpenAI.Chat.ChatCompletionOptions options,
426434
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("AOAI001")]
427435
public static Azure.AI.OpenAI.UserSecurityContext GetUserSecurityContext(this OpenAI.Chat.ChatCompletionOptions options) { throw null; }
428436
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("AOAI001")]
429-
public static void SetNewMaxCompletionTokensPropertyEnabled(this OpenAI.Chat.ChatCompletionOptions options, bool newPropertyEnabled = true) { }
430-
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("AOAI001")]
431437
public static void SetUserSecurityContext(this OpenAI.Chat.ChatCompletionOptions options, Azure.AI.OpenAI.UserSecurityContext userSecurityContext) { }
432438
}
433439
[System.Diagnostics.CodeAnalysis.ExperimentalAttribute("AOAI001")]

sdk/openai/Azure.AI.OpenAI/api/Azure.AI.OpenAI.netstandard2.0.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,15 @@ public AzureOpenAIClient(System.Uri endpoint, System.ClientModel.ApiKeyCredentia
9292
public override OpenAI.Audio.AudioClient GetAudioClient(string deploymentName) { throw null; }
9393
public override OpenAI.Batch.BatchClient GetBatchClient() { throw null; }
9494
public override OpenAI.Chat.ChatClient GetChatClient(string deploymentName) { throw null; }
95+
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
96+
public override OpenAI.Containers.ContainerClient GetContainerClient() { throw null; }
97+
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
98+
public override OpenAI.Conversations.ConversationClient GetConversationClient() { throw null; }
9599
public override OpenAI.Embeddings.EmbeddingClient GetEmbeddingClient(string deploymentName) { throw null; }
96100
public override OpenAI.Evals.EvaluationClient GetEvaluationClient() { throw null; }
97101
public override OpenAI.FineTuning.FineTuningClient GetFineTuningClient() { throw null; }
102+
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
103+
public override OpenAI.Graders.GraderClient GetGraderClient() { throw null; }
98104
public override OpenAI.Images.ImageClient GetImageClient(string deploymentName) { throw null; }
99105
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
100106
public override OpenAI.Moderations.ModerationClient GetModerationClient(string _) { throw null; }
@@ -104,6 +110,8 @@ public AzureOpenAIClient(System.Uri endpoint, System.ClientModel.ApiKeyCredentia
104110
public override OpenAI.Responses.OpenAIResponseClient GetOpenAIResponseClient(string deploymentName) { throw null; }
105111
public override OpenAI.Realtime.RealtimeClient GetRealtimeClient() { throw null; }
106112
public override OpenAI.VectorStores.VectorStoreClient GetVectorStoreClient() { throw null; }
113+
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
114+
public override OpenAI.Videos.VideoClient GetVideoClient() { throw null; }
107115
}
108116
public partial class AzureOpenAIClientOptions : System.ClientModel.Primitives.ClientPipelineOptions
109117
{
@@ -378,7 +386,6 @@ public static void AddDataSource(this OpenAI.Chat.ChatCompletionOptions options,
378386
public static Azure.AI.OpenAI.ResponseContentFilterResult GetResponseContentFilterResult(this OpenAI.Chat.ChatCompletion chatCompletion) { throw null; }
379387
public static Azure.AI.OpenAI.ResponseContentFilterResult GetResponseContentFilterResult(this OpenAI.Chat.StreamingChatCompletionUpdate chatUpdate) { throw null; }
380388
public static Azure.AI.OpenAI.UserSecurityContext GetUserSecurityContext(this OpenAI.Chat.ChatCompletionOptions options) { throw null; }
381-
public static void SetNewMaxCompletionTokensPropertyEnabled(this OpenAI.Chat.ChatCompletionOptions options, bool newPropertyEnabled = true) { }
382389
public static void SetUserSecurityContext(this OpenAI.Chat.ChatCompletionOptions options, Azure.AI.OpenAI.UserSecurityContext userSecurityContext) { }
383390
}
384391
public partial class AzureSearchChatDataSource : Azure.AI.OpenAI.Chat.ChatDataSource, System.ClientModel.Primitives.IJsonModel<Azure.AI.OpenAI.Chat.AzureSearchChatDataSource>, System.ClientModel.Primitives.IPersistableModel<Azure.AI.OpenAI.Chat.AzureSearchChatDataSource>

sdk/openai/Azure.AI.OpenAI/src/Azure.AI.OpenAI.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
<TargetFrameworks>$(RequiredTargetFrameworks)</TargetFrameworks>
1111
<GenerateAPIListing>true</GenerateAPIListing>
1212
<NoWarn>$(NoWarn);CS1591;AZC0012;AZC0102;CS8002;CS0436;AZC0112;OPENAI001;OPENAI002;AOAI001</NoWarn>
13+
<!-- For System.ClientModel JsonPatch support -->
14+
<NoWarn>$(NoWarn);SCME0001</NoWarn>
1315
<!-- Needs System.ClientModel 1.5.0 in order to add the context and use the new overloads -->
1416
<!-- After this https://github.com/Azure/azure-sdk-for-net/issues/49916 we can remove this no warn -->
1517
<NoWarn>$(NoWarn);AZC0150</NoWarn>
@@ -41,7 +43,7 @@
4143
</When>
4244
<Otherwise>
4345
<PropertyGroup>
44-
<VersionPrefix>2.5.0</VersionPrefix>
46+
<VersionPrefix>2.7.0</VersionPrefix>
4547
<VersionSuffix>beta.1</VersionSuffix>
4648
</PropertyGroup>
4749
</Otherwise>

sdk/openai/Azure.AI.OpenAI/src/Custom/AzureOpenAIClient.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@
3838
using Azure.AI.OpenAI.Responses;
3939
using OpenAI.Evals;
4040
using Azure.AI.OpenAI.Evals;
41+
using OpenAI.Conversations;
42+
using System.Text;
43+
using OpenAI.Containers;
44+
using OpenAI.Graders;
45+
using OpenAI.Videos;
4146
#endif
4247

4348
#pragma warning disable AZC0007
@@ -295,6 +300,34 @@ public override OpenAIResponseClient GetOpenAIResponseClient(string deploymentNa
295300
return new AzureOpenAIResponseClient(Pipeline, deploymentName, _endpoint, _options);
296301
}
297302

303+
[EditorBrowsable(EditorBrowsableState.Never)]
304+
public override ConversationClient GetConversationClient()
305+
{
306+
ThrowUnsupportedAreaException(nameof(ConversationClient));
307+
return null;
308+
}
309+
310+
[EditorBrowsable(EditorBrowsableState.Never)]
311+
public override ContainerClient GetContainerClient()
312+
{
313+
ThrowUnsupportedAreaException(nameof(ContainerClient));
314+
return null;
315+
}
316+
317+
[EditorBrowsable(EditorBrowsableState.Never)]
318+
public override GraderClient GetGraderClient()
319+
{
320+
ThrowUnsupportedAreaException(nameof(GraderClient));
321+
return null;
322+
}
323+
324+
[EditorBrowsable(EditorBrowsableState.Never)]
325+
public override VideoClient GetVideoClient()
326+
{
327+
ThrowUnsupportedAreaException(nameof(VideoClient));
328+
return null;
329+
}
330+
298331
private static ClientPipeline CreatePipeline(PipelinePolicy authenticationPolicy, AzureOpenAIClientOptions options)
299332
=> ClientPipeline.Create(
300333
options ?? new(),
@@ -383,6 +416,16 @@ private static PipelinePolicy CreateAddUserDefinedDefaultQueryParametersPolicy(A
383416
});
384417
}
385418

419+
private static void ThrowUnsupportedAreaException(string clientName)
420+
{
421+
StringBuilder builder = new();
422+
builder.AppendLine(clientName + " use is not supported via this library.");
423+
builder.AppendLine();
424+
builder.Append("Please use " + nameof(OpenAIClient) + " with appropriate direct endpoint "
425+
+ "configuration for access to the latest features.");
426+
throw new InvalidOperationException(builder.ToString());
427+
}
428+
386429
private static readonly string s_userAgentHeaderKey = "User-Agent";
387430
private static readonly string s_clientRequestIdHeaderKey = "x-ms-client-request-id";
388431
private static PipelineMessageClassifier s_pipelineMessageClassifier;

sdk/openai/Azure.AI.OpenAI/src/Custom/Chat/AzureChatClient.cs

Lines changed: 8 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,14 @@ protected AzureChatClient()
4242
/// <inheritdoc/>
4343
public override Task<ClientResult<ChatCompletion>> CompleteChatAsync(IEnumerable<ChatMessage> messages, ChatCompletionOptions options = null, CancellationToken cancellationToken = default)
4444
{
45-
PostfixSwapMaxTokens(ref options);
45+
RefreshMaxTokenSerialization(ref options);
4646
return base.CompleteChatAsync(messages, options, cancellationToken);
4747
}
4848

4949
/// <inheritdoc/>
5050
public override ClientResult<ChatCompletion> CompleteChat(IEnumerable<ChatMessage> messages, ChatCompletionOptions options = null, CancellationToken cancellationToken = default)
5151
{
52-
PostfixSwapMaxTokens(ref options);
52+
RefreshMaxTokenSerialization(ref options);
5353
return base.CompleteChat(messages, options, cancellationToken);
5454
}
5555

@@ -65,15 +65,15 @@ public override CollectionResult<StreamingChatCompletionUpdate> CompleteChatStre
6565
public override AsyncCollectionResult<StreamingChatCompletionUpdate> CompleteChatStreamingAsync(IEnumerable<ChatMessage> messages, ChatCompletionOptions options = null, CancellationToken cancellationToken = default)
6666
{
6767
PostfixClearStreamOptions(messages, ref options);
68-
PostfixSwapMaxTokens(ref options);
68+
RefreshMaxTokenSerialization(ref options);
6969
return base.CompleteChatStreamingAsync(messages, options, cancellationToken);
7070
}
7171

7272
/// <inheritdoc/>
7373
public override CollectionResult<StreamingChatCompletionUpdate> CompleteChatStreaming(IEnumerable<ChatMessage> messages, ChatCompletionOptions options = null, CancellationToken cancellationToken = default)
7474
{
7575
PostfixClearStreamOptions(messages, ref options);
76-
PostfixSwapMaxTokens(ref options);
76+
RefreshMaxTokenSerialization(ref options);
7777
return base.CompleteChatStreaming(messages, options, cancellationToken);
7878
}
7979

@@ -86,16 +86,14 @@ public override CollectionResult<StreamingChatCompletionUpdate> CompleteChatStre
8686
*/
8787
private static void PostfixClearStreamOptions(IEnumerable<ChatMessage> messages, ref ChatCompletionOptions options)
8888
{
89-
if (AdditionalPropertyHelpers
90-
.GetAdditionalPropertyAsListOfChatDataSource(options?.SerializedAdditionalRawData, "data_sources")?.Count > 0
89+
if (options?.Patch.GetBytesOrDefaultEx("$.data_sources"u8) is not null
9190
|| messages?.Any(
9291
message => message?.Content?.Any(
9392
contentPart => contentPart?.Kind == ChatMessageContentPartKind.Image) == true)
9493
== true)
9594
{
9695
options ??= new();
97-
options.SerializedAdditionalRawData ??= new Dictionary<string, BinaryData>();
98-
AdditionalPropertyHelpers.SetEmptySentinelValue(options.SerializedAdditionalRawData, "stream_options");
96+
options.Patch.Remove("$.stream_options"u8);
9997
}
10098
}
10199

@@ -110,56 +108,9 @@ private static void PostfixClearStreamOptions(IEnumerable<ChatMessage> messages,
110108
* - Otherwise, serialization of max_completion_tokens is blocked and an override serialization of the
111109
* corresponding max_tokens value is established
112110
*/
113-
private static void PostfixSwapMaxTokens(ref ChatCompletionOptions options)
111+
private static void RefreshMaxTokenSerialization(ref ChatCompletionOptions options)
114112
{
115113
options ??= new();
116-
bool valueIsSet = options.MaxOutputTokenCount is not null;
117-
bool oldPropertyBlocked = AdditionalPropertyHelpers.GetIsEmptySentinelValue(options.SerializedAdditionalRawData, "max_tokens");
118-
119-
if (valueIsSet)
120-
{
121-
if (!oldPropertyBlocked)
122-
{
123-
options.SerializedAdditionalRawData ??= new ChangeTrackingDictionary<string, BinaryData>();
124-
AdditionalPropertyHelpers.SetEmptySentinelValue(options.SerializedAdditionalRawData, "max_completion_tokens");
125-
126-
using MemoryStream stream = new();
127-
using Utf8JsonWriter writer = new(stream);
128-
129-
if (options.MaxOutputTokenCount != null)
130-
{
131-
writer.WriteNumberValue(options.MaxOutputTokenCount.Value);
132-
}
133-
else
134-
{
135-
writer.WriteNullValue();
136-
}
137-
138-
writer.Flush();
139-
140-
options.SerializedAdditionalRawData["max_tokens"] = BinaryData.FromBytes(stream.ToArray());
141-
}
142-
else
143-
{
144-
// Allow standard serialization to the new property to occur; remove overrides
145-
if (options.SerializedAdditionalRawData.ContainsKey("max_completion_tokens"))
146-
{
147-
options.SerializedAdditionalRawData.Remove("max_completion_tokens");
148-
}
149-
}
150-
}
151-
else
152-
{
153-
if (!AdditionalPropertyHelpers.GetIsEmptySentinelValue(options.SerializedAdditionalRawData, "max_tokens")
154-
&& options.SerializedAdditionalRawData?.ContainsKey("max_tokens") == true)
155-
{
156-
options.SerializedAdditionalRawData.Remove("max_tokens");
157-
}
158-
if (!AdditionalPropertyHelpers.GetIsEmptySentinelValue(options.SerializedAdditionalRawData, "max_completion_tokens")
159-
&& options.SerializedAdditionalRawData?.ContainsKey("max_completion_tokens") == true)
160-
{
161-
options.SerializedAdditionalRawData.Remove("max_completion_tokens");
162-
}
163-
}
114+
options.SetMaxTokenPatchValues();
164115
}
165116
}

0 commit comments

Comments
 (0)