Skip to content

Commit 346ae44

Browse files
committed
merge
2 parents 12b930e + 915c39d commit 346ae44

20 files changed

+479
-33
lines changed

api/OpenAI.net8.0.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,7 @@ public class AudioClient {
10561056
public AudioClient(string model, ApiKeyCredential credential, OpenAIClientOptions options);
10571057
public AudioClient(string model, ApiKeyCredential credential);
10581058
public AudioClient(string model, string apiKey);
1059+
[Experimental("OPENAI001")]
10591060
public string Model { get; }
10601061
public ClientPipeline Pipeline { get; }
10611062
public virtual ClientResult GenerateSpeech(BinaryContent content, RequestOptions options = null);
@@ -1403,7 +1404,12 @@ public class ChatClient {
14031404
protected internal ChatClient(ClientPipeline pipeline, string model, OpenAIClientOptions options);
14041405
public ChatClient(string model, ApiKeyCredential credential, OpenAIClientOptions options);
14051406
public ChatClient(string model, ApiKeyCredential credential);
1407+
[Experimental("OPENAI001")]
1408+
public ChatClient(string model, AuthenticationPolicy authenticationPolicy, OpenAIClientOptions options);
1409+
[Experimental("OPENAI001")]
1410+
public ChatClient(string model, AuthenticationPolicy authenticationPolicy);
14061411
public ChatClient(string model, string apiKey);
1412+
[Experimental("OPENAI001")]
14071413
public string Model { get; }
14081414
public ClientPipeline Pipeline { get; }
14091415
public virtual ClientResult<ChatCompletion> CompleteChat(params ChatMessage[] messages);
@@ -2310,6 +2316,7 @@ public class EmbeddingClient {
23102316
public EmbeddingClient(string model, ApiKeyCredential credential, OpenAIClientOptions options);
23112317
public EmbeddingClient(string model, ApiKeyCredential credential);
23122318
public EmbeddingClient(string model, string apiKey);
2319+
[Experimental("OPENAI001")]
23132320
public string Model { get; }
23142321
public ClientPipeline Pipeline { get; }
23152322
public virtual ClientResult<OpenAIEmbedding> GenerateEmbedding(string input, EmbeddingGenerationOptions options = null, CancellationToken cancellationToken = default);
@@ -3273,6 +3280,7 @@ public class ImageClient {
32733280
public ImageClient(string model, ApiKeyCredential credential, OpenAIClientOptions options);
32743281
public ImageClient(string model, ApiKeyCredential credential);
32753282
public ImageClient(string model, string apiKey);
3283+
[Experimental("OPENAI001")]
32763284
public string Model { get; }
32773285
public ClientPipeline Pipeline { get; }
32783286
public virtual ClientResult<GeneratedImage> GenerateImage(string prompt, ImageGenerationOptions options = null, CancellationToken cancellationToken = default);
@@ -3460,6 +3468,7 @@ public class ModerationClient {
34603468
public ModerationClient(string model, ApiKeyCredential credential, OpenAIClientOptions options);
34613469
public ModerationClient(string model, ApiKeyCredential credential);
34623470
public ModerationClient(string model, string apiKey);
3471+
[Experimental("OPENAI001")]
34633472
public string Model { get; }
34643473
public ClientPipeline Pipeline { get; }
34653474
public virtual ClientResult ClassifyText(BinaryContent content, RequestOptions options = null);
@@ -4642,6 +4651,14 @@ public class OpenAIResponseClient {
46424651
public virtual AsyncCollectionResult<StreamingResponseUpdate> GetResponseStreamingAsync(string responseId, int? startingAfter = null, CancellationToken cancellationToken = default);
46434652
}
46444653
[Experimental("OPENAI001")]
4654+
public static class OpenAIResponsesModelFactory {
4655+
public static MessageResponseItem MessageResponseItem(string id = null, MessageRole role = MessageRole.Assistant, MessageStatus? status = null);
4656+
public static OpenAIResponse OpenAIResponse(string id = null, DateTimeOffset createdAt = default, ResponseStatus? status = null, ResponseError error = null, ResponseTokenUsage usage = null, string endUserId = null, ResponseReasoningOptions reasoningOptions = null, int? maxOutputTokenCount = null, ResponseTextOptions textOptions = null, ResponseTruncationMode? truncationMode = null, ResponseIncompleteStatusDetails incompleteStatusDetails = null, IEnumerable<ResponseItem> outputItems = null, bool parallelToolCallsEnabled = false, ResponseToolChoice toolChoice = null, string model = null, IDictionary<string, string> metadata = null, float? temperature = null, float? topP = null, string previousResponseId = null, bool? background = null, string instructions = null, IEnumerable<ResponseTool> tools = null);
4657+
public static ReasoningResponseItem ReasoningResponseItem(string id = null, string encryptedContent = null, ReasoningStatus? status = null, IEnumerable<ReasoningSummaryPart> summaryParts = null);
4658+
public static ReasoningResponseItem ReasoningResponseItem(string id = null, string encryptedContent = null, ReasoningStatus? status = null, string summaryText = null);
4659+
public static ReferenceResponseItem ReferenceResponseItem(string id = null);
4660+
}
4661+
[Experimental("OPENAI001")]
46454662
public class ReasoningResponseItem : ResponseItem, IJsonModel<ReasoningResponseItem>, IPersistableModel<ReasoningResponseItem> {
46464663
public ReasoningResponseItem(IEnumerable<ReasoningSummaryPart> summaryParts);
46474664
public ReasoningResponseItem(string summaryText);

api/OpenAI.netstandard2.0.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,6 +1266,8 @@ public class ChatClient {
12661266
protected internal ChatClient(ClientPipeline pipeline, string model, OpenAIClientOptions options);
12671267
public ChatClient(string model, ApiKeyCredential credential, OpenAIClientOptions options);
12681268
public ChatClient(string model, ApiKeyCredential credential);
1269+
public ChatClient(string model, AuthenticationPolicy authenticationPolicy, OpenAIClientOptions options);
1270+
public ChatClient(string model, AuthenticationPolicy authenticationPolicy);
12691271
public ChatClient(string model, string apiKey);
12701272
public string Model { get; }
12711273
public ClientPipeline Pipeline { get; }
@@ -4111,6 +4113,13 @@ public class OpenAIResponseClient {
41114113
public virtual CollectionResult<StreamingResponseUpdate> GetResponseStreaming(string responseId, int? startingAfter = null, CancellationToken cancellationToken = default);
41124114
public virtual AsyncCollectionResult<StreamingResponseUpdate> GetResponseStreamingAsync(string responseId, int? startingAfter = null, CancellationToken cancellationToken = default);
41134115
}
4116+
public static class OpenAIResponsesModelFactory {
4117+
public static MessageResponseItem MessageResponseItem(string id = null, MessageRole role = MessageRole.Assistant, MessageStatus? status = null);
4118+
public static OpenAIResponse OpenAIResponse(string id = null, DateTimeOffset createdAt = default, ResponseStatus? status = null, ResponseError error = null, ResponseTokenUsage usage = null, string endUserId = null, ResponseReasoningOptions reasoningOptions = null, int? maxOutputTokenCount = null, ResponseTextOptions textOptions = null, ResponseTruncationMode? truncationMode = null, ResponseIncompleteStatusDetails incompleteStatusDetails = null, IEnumerable<ResponseItem> outputItems = null, bool parallelToolCallsEnabled = false, ResponseToolChoice toolChoice = null, string model = null, IDictionary<string, string> metadata = null, float? temperature = null, float? topP = null, string previousResponseId = null, bool? background = null, string instructions = null, IEnumerable<ResponseTool> tools = null);
4119+
public static ReasoningResponseItem ReasoningResponseItem(string id = null, string encryptedContent = null, ReasoningStatus? status = null, IEnumerable<ReasoningSummaryPart> summaryParts = null);
4120+
public static ReasoningResponseItem ReasoningResponseItem(string id = null, string encryptedContent = null, ReasoningStatus? status = null, string summaryText = null);
4121+
public static ReferenceResponseItem ReferenceResponseItem(string id = null);
4122+
}
41144123
public class ReasoningResponseItem : ResponseItem, IJsonModel<ReasoningResponseItem>, IPersistableModel<ReasoningResponseItem> {
41154124
public ReasoningResponseItem(IEnumerable<ReasoningSummaryPart> summaryParts);
41164125
public ReasoningResponseItem(string summaryText);

codegen/generator/src/OpenAILibraryVisitor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public class OpenAILibraryVisitor : ScmLibraryVisitor
4343
["FunctionCallResponseItem"] = [_readonlyStatusReplacementInfo],
4444
["FunctionCallOutputResponseItem"] = [_readonlyStatusReplacementInfo],
4545
["MessageResponseItem"] = [_readonlyStatusReplacementInfo],
46+
["ReasoningResponseItem"] = [_readonlyStatusReplacementInfo],
4647
["WebSearchCallResponseItem"] = [_readonlyStatusReplacementInfo],
4748
};
4849

codegen/nuget.config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<configuration>
3+
<packageSources>
4+
<add key="generator" value="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json" />
5+
</packageSources>
6+
</configuration>

examples/Chat/Example08_ChatSerialization.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public static BinaryData SerializeMessages(IEnumerable<ChatMessage> messages)
3939
writer.WriteEndArray();
4040
writer.Flush();
4141

42-
return BinaryData.FromBytes(stream.ToArray());
42+
return BinaryData.FromBytes(stream.GetBuffer().AsMemory(0, (int)stream.Length));
4343
}
4444
#endregion
4545

src/Custom/Audio/AudioClient.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ protected internal AudioClient(ClientPipeline pipeline, string model, OpenAIClie
9191
/// <summary>
9292
/// Gets the name of the model used in requests sent to the service.
9393
/// </summary>
94+
[Experimental("OPENAI001")]
9495
public string Model => _model;
9596

9697
#region GenerateSpeech

src/Custom/Chat/ChatClient.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,37 @@ public partial class ChatClient
6262
/// <param name="options"> The options to configure the client. </param>
6363
/// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="credential"/> is null. </exception>
6464
/// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
65-
public ChatClient(string model, ApiKeyCredential credential, OpenAIClientOptions options)
65+
public ChatClient(string model, ApiKeyCredential credential, OpenAIClientOptions options) : this(model, OpenAIClient.CreateApiKeyAuthenticationPolicy(credential), options)
66+
{
67+
}
68+
69+
// CUSTOM: Added as a convenience.
70+
/// <summary> Initializes a new instance of <see cref="ChatClient"/>. </summary>
71+
/// <param name="model"> The name of the model to use in requests sent to the service. To learn more about the available models, see <see href="https://platform.openai.com/docs/models"/>. </param>
72+
/// <param name="authenticationPolicy"> The authentication policy used to authenticate with the service. </param>
73+
/// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="authenticationPolicy"/> is null. </exception>
74+
/// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
75+
[Experimental("OPENAI001")]
76+
public ChatClient(string model, AuthenticationPolicy authenticationPolicy) : this(model, authenticationPolicy, new OpenAIClientOptions())
77+
{
78+
}
79+
80+
// CUSTOM: Added as a convenience.
81+
/// <summary> Initializes a new instance of <see cref="ChatClient"/>. </summary>
82+
/// <param name="model"> The name of the model to use in requests sent to the service. To learn more about the available models, see <see href="https://platform.openai.com/docs/models"/>. </param>
83+
/// <param name="authenticationPolicy"> The authentication policy used to authenticate with the service. </param>
84+
/// <param name="options"> The options to configure the client. </param>
85+
/// <exception cref="ArgumentNullException"> <paramref name="model"/> or <paramref name="authenticationPolicy"/> is null. </exception>
86+
/// <exception cref="ArgumentException"> <paramref name="model"/> is an empty string, and was expected to be non-empty. </exception>
87+
[Experimental("OPENAI001")]
88+
public ChatClient(string model, AuthenticationPolicy authenticationPolicy, OpenAIClientOptions options)
6689
{
6790
Argument.AssertNotNullOrEmpty(model, nameof(model));
68-
Argument.AssertNotNull(credential, nameof(credential));
91+
Argument.AssertNotNull(authenticationPolicy, nameof(authenticationPolicy));
6992
options ??= new OpenAIClientOptions();
7093

7194
_model = model;
72-
Pipeline = OpenAIClient.CreatePipeline(credential, options);
95+
Pipeline = OpenAIClient.CreatePipeline(authenticationPolicy, options);
7396
_endpoint = OpenAIClient.GetEndpoint(options);
7497
_telemetry = new OpenTelemetrySource(model, _endpoint);
7598
}
@@ -101,6 +124,7 @@ protected internal ChatClient(ClientPipeline pipeline, string model, OpenAIClien
101124
/// <summary>
102125
/// Gets the name of the model used in requests sent to the service.
103126
/// </summary>
127+
[Experimental("OPENAI001")]
104128
public string Model => _model;
105129

106130
/// <summary> Generates a completion for the given chat. </summary>

src/Custom/Embeddings/EmbeddingClient.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.ClientModel;
33
using System.ClientModel.Primitives;
44
using System.Collections.Generic;
5+
using System.Diagnostics.CodeAnalysis;
56
using System.IO;
67
using System.Linq;
78
using System.Text.Json;
@@ -92,6 +93,7 @@ protected internal EmbeddingClient(ClientPipeline pipeline, string model, OpenAI
9293
/// <summary>
9394
/// Gets the name of the model used in requests sent to the service.
9495
/// </summary>
96+
[Experimental("OPENAI001")]
9597
public string Model => _model;
9698

9799
// CUSTOM: Added to simplify generating a single embedding from a string input.
@@ -217,7 +219,7 @@ private void CreateEmbeddingGenerationOptions(string input, ref EmbeddingGenerat
217219
writer.WriteStringValue(input);
218220
writer.Flush();
219221

220-
options.Input = BinaryData.FromBytes(stream.ToArray());
222+
options.Input = BinaryData.FromBytes(stream.GetBuffer().AsMemory(0, (int)stream.Length));
221223
options.Model = _model;
222224
options.EncodingFormat = InternalCreateEmbeddingRequestEncodingFormat.Base64;
223225
}
@@ -237,7 +239,7 @@ private void CreateEmbeddingGenerationOptions(IEnumerable<string> inputs, ref Em
237239
writer.WriteEndArray();
238240
writer.Flush();
239241

240-
options.Input = BinaryData.FromBytes(stream.ToArray());
242+
options.Input = BinaryData.FromBytes(stream.GetBuffer().AsMemory(0, (int)stream.Length));
241243
options.Model = _model;
242244
options.EncodingFormat = InternalCreateEmbeddingRequestEncodingFormat.Base64;
243245
}
@@ -264,7 +266,7 @@ private void CreateEmbeddingGenerationOptions(IEnumerable<ReadOnlyMemory<int>> i
264266
writer.WriteEndArray();
265267
writer.Flush();
266268

267-
options.Input = BinaryData.FromBytes(stream.ToArray());
269+
options.Input = BinaryData.FromBytes(stream.GetBuffer().AsMemory(0, (int)stream.Length));
268270
options.Model = _model;
269271
options.EncodingFormat = InternalCreateEmbeddingRequestEncodingFormat.Base64;
270272
}

src/Custom/Embeddings/OpenAIEmbedding.cs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Buffers.Text;
55
using System.Collections.Generic;
66
using System.Runtime.InteropServices;
7+
using System.Text.Json;
78

89
namespace OpenAI.Embeddings;
910

@@ -107,13 +108,18 @@ internal OpenAIEmbedding(int index, ReadOnlyMemory<float> vector)
107108
// CUSTOM: Implemented custom logic to transform from BinaryData to ReadOnlyMemory<float>.
108109
private static ReadOnlyMemory<float> ConvertToVectorOfFloats(BinaryData binaryData)
109110
{
110-
ReadOnlySpan<byte> base64 = binaryData.ToMemory().Span;
111+
ReadOnlySpan<byte> bytes = binaryData.ToMemory().Span;
111112

112113
// Remove quotes around base64 string.
113-
if (base64.Length < 2 || base64[0] != (byte)'"' || base64[base64.Length - 1] != (byte)'"')
114+
if (bytes.Length > 2 && bytes[0] == (byte)'"' && bytes[bytes.Length - 1] == (byte)'"')
114115
{
115-
ThrowInvalidData();
116+
return ConvertFromBase64(bytes);
116117
}
118+
return ConvertFromJsonArray(binaryData);
119+
}
120+
121+
private static ReadOnlyMemory<float> ConvertFromBase64(ReadOnlySpan<byte> base64)
122+
{
117123
base64 = base64.Slice(1, base64.Length - 2);
118124

119125
// Decode base64 string to bytes.
@@ -153,7 +159,33 @@ private static ReadOnlyMemory<float> ConvertToVectorOfFloats(BinaryData binaryDa
153159
}
154160
}
155161

156-
static void ThrowInvalidData() =>
157-
throw new FormatException("The input is not a valid Base64 string of encoded floats.");
162+
static void ThrowInvalidData()
163+
=> throw new FormatException("The input is not a valid Base64 string of encoded floats.");
164+
}
165+
166+
private static ReadOnlyMemory<float> ConvertFromJsonArray(BinaryData jsonArray)
167+
{
168+
using JsonDocument document = JsonDocument.Parse(jsonArray);
169+
JsonElement array = document.RootElement;
170+
if (array.ValueKind != JsonValueKind.Array)
171+
{
172+
throw new FormatException("The input is not a valid JSON array");
173+
}
174+
175+
int arrayLength = array.GetArrayLength();
176+
float[] vector = new float[arrayLength];
177+
int index = 0;
178+
try
179+
{
180+
foreach (JsonElement value in array.EnumerateArray())
181+
{
182+
vector[index++] = value.GetSingle();
183+
}
184+
return vector.AsMemory();
185+
}
186+
catch
187+
{
188+
throw new FormatException("The input is not a valid JSON array of float values");
189+
}
158190
}
159191
}

src/Custom/Images/ImageClient.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.ClientModel;
33
using System.ClientModel.Primitives;
4+
using System.Diagnostics.CodeAnalysis;
45
using System.IO;
56
using System.Linq;
67
using System.Threading;
@@ -86,10 +87,11 @@ protected internal ImageClient(ClientPipeline pipeline, string model, OpenAIClie
8687
Pipeline = pipeline;
8788
_endpoint = OpenAIClient.GetEndpoint(options);
8889
}
89-
90+
9091
/// <summary>
9192
/// Gets the name of the model used in requests sent to the service.
9293
/// </summary>
94+
[Experimental("OPENAI001")]
9395
public string Model => _model;
9496

9597
#region GenerateImages

0 commit comments

Comments
 (0)