Skip to content

Commit 13a9c68

Browse files
authored
Remove constructors that do not explicitly take a credential parameter (#175)
- Removed client constructors that do not explicitly take an API key parameter or an endpoint via an `OpenAIClientOptions` parameter, making it clearer how to appropriately instantiate a client. - Removed the endpoint parameter from all client constructors, making it clearer that an alternative endpoint must be specified via the `OpenAIClientOptions` parameter. - Removed `OpenAIClient`'s `Endpoint` `protected` property. - Made `OpenAIClient`'s constructor that takes a `ClientPipeline` parameter `protected internal` instead of just `protected`. - Renamed the `User` property in applicable Options classes to `EndUserId`, making its purpose clearer.
1 parent b1ce397 commit 13a9c68

File tree

52 files changed

+1360
-1411
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+1360
-1411
lines changed

CHANGELOG.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,21 @@
55
### Features Added
66

77
- Added the following model factories (static classes that can be used to instantiate OpenAI models for mocking in non-live test scenarios):
8-
- `OpenAIAudioModelFactory` in the `OpenAI.Audio` namespace
9-
- `OpenAIEmbeddingsModelFactory` in the `OpenAI.Embeddings` namespace
10-
- `OpenAIFilesModelFactory` in the `OpenAI.Files` namespace
11-
- `OpenAIImagesModelFactory` in the `OpenAI.Images` namespace
12-
- `OpenAIModelsModelFactory` in the `OpenAI.Models` namespace
13-
- `OpenAIModerationsModelFactory` in the `OpenAI.Moderations` namespace
8+
- `OpenAIAudioModelFactory` in the `OpenAI.Audio` namespace (commit_hash)
9+
- `OpenAIEmbeddingsModelFactory` in the `OpenAI.Embeddings` namespace (commit_hash)
10+
- `OpenAIFilesModelFactory` in the `OpenAI.Files` namespace (commit_hash)
11+
- `OpenAIImagesModelFactory` in the `OpenAI.Images` namespace (commit_hash)
12+
- `OpenAIModelsModelFactory` in the `OpenAI.Models` namespace (commit_hash)
13+
- `OpenAIModerationsModelFactory` in the `OpenAI.Moderations` namespace (commit_hash)
1414

1515
### Breaking Changes
1616

17+
- Removed client constructors that do not explicitly take an API key parameter or an endpoint via an `OpenAIClientOptions` parameter, making it clearer how to appropriately instantiate a client. (commit_hash)
18+
- Removed the endpoint parameter from all client constructors, making it clearer that an alternative endpoint must be specified via the `OpenAIClientOptions` parameter. (commit_hash)
19+
- Removed `OpenAIClient`'s `Endpoint` `protected` property. (commit_hash)
20+
- Made `OpenAIClient`'s constructor that takes a `ClientPipeline` parameter `protected internal` instead of just `protected`. (commit_hash)
21+
- Renamed the `User` property in applicable Options classes to `EndUserId`, making its purpose clearer. (commit_hash)
22+
1723
### Bugs Fixed
1824

1925
### Other Changes

api/OpenAI.netstandard2.0.cs

Lines changed: 41 additions & 46 deletions
Large diffs are not rendered by default.

examples/Assistants/Example01_RetrievalAugmentedGeneration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,6 @@ PageCollection<ThreadMessage> messagePages
145145
// Optionally, delete any persistent resources you no longer need.
146146
_ = assistantClient.DeleteThread(threadRun.ThreadId);
147147
_ = assistantClient.DeleteAssistant(assistant);
148-
_ = fileClient.DeleteFile(salesFile);
148+
_ = fileClient.DeleteFile(salesFile.Id);
149149
}
150150
}

examples/Assistants/Example01_RetrievalAugmentedGenerationAsync.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,6 @@ AsyncPageCollection<ThreadMessage> messagePages
146146
// Optionally, delete any persistent resources you no longer need.
147147
_ = await assistantClient.DeleteThreadAsync(threadRun.ThreadId);
148148
_ = await assistantClient.DeleteAssistantAsync(assistant);
149-
_ = await fileClient.DeleteFileAsync(salesFile);
149+
_ = await fileClient.DeleteFileAsync(salesFile.Id);
150150
}
151151
}

examples/Assistants/Example04_AllTheTools.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ static string GetNameOfFamilyMember(string relation)
4545
};
4646

4747
#region Upload a mock file for use with file search
48-
FileClient fileClient = new();
48+
FileClient fileClient = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
4949
OpenAIFileInfo favoriteNumberFile = fileClient.UploadFile(
5050
BinaryData.FromString("""
5151
This file contains the favorite numbers for individuals.
@@ -59,7 +59,7 @@ static string GetNameOfFamilyMember(string relation)
5959
#endregion
6060

6161
#region Create an assistant with functions, file search, and code interpreter all enabled
62-
AssistantClient client = new();
62+
AssistantClient client = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
6363
Assistant assistant = client.CreateAssistant("gpt-4-turbo", new AssistantCreationOptions()
6464
{
6565
Instructions = "Use functions to resolve family relations into the names of people. Use file search to "

examples/Assistants/Example05_AssistantsWithVision.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public void Example05_AssistantsWithVision()
6565
}
6666

6767
// Delete temporary resources, if desired
68-
_ = fileClient.DeleteFile(pictureOfAppleFile);
68+
_ = fileClient.DeleteFile(pictureOfAppleFile.Id);
6969
_ = assistantClient.DeleteThread(thread);
7070
_ = assistantClient.DeleteAssistant(assistant);
7171
}

examples/Assistants/Example05_AssistantsWithVisionAsync.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public async Task Example05_AssistantsWithVisionAsync()
6565
}
6666
}
6767

68-
_ = await fileClient.DeleteFileAsync(pictureOfAppleFile);
68+
_ = await fileClient.DeleteFileAsync(pictureOfAppleFile.Id);
6969
_ = await assistantClient.DeleteThreadAsync(thread);
7070
_ = await assistantClient.DeleteAssistantAsync(assistant);
7171
}

examples/CombinationExamples.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public partial class CombinationExamples
1515
public void AlpacaArtAssessor()
1616
{
1717
// First, we create an image using dall-e-3:
18-
ImageClient imageClient = new("dall-e-3");
18+
ImageClient imageClient = new("dall-e-3", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
1919
ClientResult<GeneratedImage> imageResult = imageClient.GenerateImage(
2020
"a majestic alpaca on a mountain ridge, backed by an expansive blue sky accented with sparse clouds",
2121
new()
@@ -28,7 +28,7 @@ public void AlpacaArtAssessor()
2828
Console.WriteLine($"Majestic alpaca available at:\n{imageGeneration.ImageUri.AbsoluteUri}");
2929

3030
// Now, we'll ask a cranky art critic to evaluate the image using gpt-4-vision-preview:
31-
ChatClient chatClient = new("gpt-4-vision-preview");
31+
ChatClient chatClient = new("gpt-4o-mini", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
3232
ChatCompletion chatCompletion = chatClient.CompleteChat(
3333
[
3434
new SystemChatMessage("Assume the role of a cranky art critic. When asked to describe or "
@@ -47,7 +47,7 @@ public void AlpacaArtAssessor()
4747
Console.WriteLine($"Art critique of majestic alpaca:\n{chatResponseText}");
4848

4949
// Finally, we'll get some text-to-speech for that critical evaluation using tts-1-hd:
50-
AudioClient audioClient = new("tts-1-hd");
50+
AudioClient audioClient = new("tts-1-hd", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
5151
ClientResult<BinaryData> ttsResult = audioClient.GenerateSpeechFromText(
5252
text: chatResponseText,
5353
GeneratedSpeechVoice.Fable,
@@ -69,7 +69,7 @@ public void AlpacaArtAssessor()
6969
public async Task CuriousCreatureCreator()
7070
{
7171
// First, we'll use gpt-4 to have a creative helper imagine a twist on a household pet
72-
ChatClient creativeWriterClient = new("gpt-4");
72+
ChatClient creativeWriterClient = new("gpt-4o-mini", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
7373
ClientResult<ChatCompletion> creativeWriterResult = creativeWriterClient.CompleteChat(
7474
[
7575
new SystemChatMessage("You're a creative helper that specializes in brainstorming designs for concepts that fuse ordinary, mundane items with a fantastical touch. In particular, you can provide good one-paragraph descriptions of concept images."),
@@ -83,7 +83,7 @@ public async Task CuriousCreatureCreator()
8383
Console.WriteLine($"Creative helper's creature description:\n{description}");
8484

8585
// Asynchronously, in parallel to the next steps, we'll get the creative description in the voice of Onyx
86-
AudioClient ttsClient = new("tts-1-hd");
86+
AudioClient ttsClient = new("tts-1-hd", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
8787
Task<ClientResult<BinaryData>> imageDescriptionAudioTask = ttsClient.GenerateSpeechFromTextAsync(
8888
description,
8989
GeneratedSpeechVoice.Onyx,
@@ -103,7 +103,7 @@ public async Task CuriousCreatureCreator()
103103
});
104104

105105
// Meanwhile, we'll use dall-e-3 to generate a rendition of our LLM artist's vision
106-
ImageClient imageGenerationClient = new("dall-e-3");
106+
ImageClient imageGenerationClient = new("dall-e-3", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
107107
ClientResult<GeneratedImage> imageGenerationResult = await imageGenerationClient.GenerateImageAsync(
108108
description,
109109
new ImageGenerationOptions()
@@ -115,7 +115,7 @@ public async Task CuriousCreatureCreator()
115115
Console.WriteLine($"Creature image available at:\n{imageLocation.AbsoluteUri}");
116116

117117
// Now, we'll use gpt-4-vision-preview to get a hopelessly taken assessment from a usually exigent art connoisseur
118-
ChatClient imageCriticClient = new("gpt-4-vision-preview");
118+
ChatClient imageCriticClient = new("gpt-4o-mini", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
119119
ClientResult<ChatCompletion> criticalAppraisalResult = await imageCriticClient.CompleteChatAsync(
120120
[
121121
new SystemChatMessage("Assume the role of an art critic. Although usually cranky and occasionally even referred to as a 'curmudgeon', you're somehow entirely smitten with the subject presented to you and, despite your best efforts, can't help but lavish praise when you're asked to appraise a provided image."),

src/Custom/Assistants/AssistantClient.cs

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010

1111
namespace OpenAI.Assistants;
1212

13-
/// <summary>
14-
/// The service client for OpenAI assistants.
15-
/// </summary>
13+
/// <summary> The service client for OpenAI assistants operations. </summary>
1614
[Experimental("OPENAI001")]
1715
[CodeGenClient("Assistants")]
1816
[CodeGenSuppress("AssistantClient", typeof(ClientPipeline), typeof(ApiKeyCredential), typeof(Uri))]
@@ -32,47 +30,53 @@ public partial class AssistantClient
3230
private readonly InternalAssistantRunClient _runSubClient;
3331
private readonly InternalAssistantThreadClient _threadSubClient;
3432

35-
/// <summary>
36-
/// Initializes a new instance of <see cref="AssistantClient"/> that will use an API key when authenticating.
37-
/// </summary>
38-
/// <param name="credential"> The API key used to authenticate with the service endpoint. </param>
39-
/// <param name="options"> Additional options to customize the client. </param>
40-
/// <exception cref="ArgumentNullException"> The provided <paramref name="credential"/> was null. </exception>
41-
public AssistantClient(ApiKeyCredential credential, OpenAIClientOptions options = default)
42-
: this(
43-
OpenAIClient.CreatePipeline(OpenAIClient.GetApiKey(credential, requireExplicitCredential: true), options),
44-
OpenAIClient.GetEndpoint(options),
45-
options)
46-
{ }
33+
// CUSTOM:
34+
// - Used a custom pipeline.
35+
// - Demoted the endpoint parameter to be a property in the options class.
36+
/// <summary> Initializes a new instance of <see cref="AssistantClient">. </summary>
37+
/// <param name="credential"> The API key to authenticate with the service. </param>
38+
/// <exception cref="ArgumentNullException"> <paramref name="credential"/> is null. </exception>
39+
public AssistantClient(ApiKeyCredential credential) : this(credential, new OpenAIClientOptions())
40+
{
41+
}
4742

48-
/// <summary>
49-
/// Initializes a new instance of <see cref="AssistantClient"/> that will use an API key from the OPENAI_API_KEY
50-
/// environment variable when authenticating.
51-
/// </summary>
52-
/// <remarks>
53-
/// To provide an explicit credential instead of using the environment variable, use an alternate constructor like
54-
/// <see cref="AssistantClient(ApiKeyCredential,OpenAIClientOptions)"/>.
55-
/// </remarks>
56-
/// <param name="options"> Additional options to customize the client. </param>
57-
/// <exception cref="InvalidOperationException"> The OPENAI_API_KEY environment variable was not found. </exception>
58-
public AssistantClient(OpenAIClientOptions options = default)
59-
: this(
60-
OpenAIClient.CreatePipeline(OpenAIClient.GetApiKey(), options),
61-
OpenAIClient.GetEndpoint(options),
62-
options)
63-
{ }
64-
65-
/// <summary> Initializes a new instance of <see cref="AssistantClient"/>. </summary>
66-
/// <param name="pipeline"> The HTTP pipeline for sending and receiving REST requests and responses. </param>
67-
/// <param name="endpoint"> OpenAI Endpoint. </param>
68-
/// <param name="options"> Client-wide options to propagate settings from. </param>
69-
protected internal AssistantClient(ClientPipeline pipeline, Uri endpoint, OpenAIClientOptions options)
43+
// CUSTOM:
44+
// - Used a custom pipeline.
45+
// - Demoted the endpoint parameter to be a property in the options class.
46+
/// <summary> Initializes a new instance of <see cref="AssistantClient">. </summary>
47+
/// <param name="credential"> The API key to authenticate with the service. </param>
48+
/// <param name="options"> The options to configure the client. </param>
49+
/// <exception cref="ArgumentNullException"> <paramref name="credential"/> is null. </exception>
50+
public AssistantClient(ApiKeyCredential credential, OpenAIClientOptions options)
7051
{
52+
Argument.AssertNotNull(credential, nameof(credential));
53+
options ??= new OpenAIClientOptions();
54+
55+
_pipeline = OpenAIClient.CreatePipeline(credential, options);
56+
_endpoint = OpenAIClient.GetEndpoint(options);
57+
_messageSubClient = new(_pipeline, options);
58+
_runSubClient = new(_pipeline, options);
59+
_threadSubClient = new(_pipeline, options);
60+
}
61+
62+
// CUSTOM:
63+
// - Used a custom pipeline.
64+
// - Demoted the endpoint parameter to be a property in the options class.
65+
// - Made protected.
66+
/// <summary> Initializes a new instance of <see cref="AssistantClient">. </summary>
67+
/// <param name="pipeline"> The HTTP pipeline to send and receive REST requests and responses. </param>
68+
/// <param name="options"> The options to configure the client. </param>
69+
/// <exception cref="ArgumentNullException"> <paramref name="pipeline"/> is null. </exception>
70+
protected internal AssistantClient(ClientPipeline pipeline, OpenAIClientOptions options)
71+
{
72+
Argument.AssertNotNull(pipeline, nameof(pipeline));
73+
options ??= new OpenAIClientOptions();
74+
7175
_pipeline = pipeline;
72-
_endpoint = endpoint;
73-
_messageSubClient = new(_pipeline, _endpoint, options);
74-
_runSubClient = new(_pipeline, _endpoint, options);
75-
_threadSubClient = new(_pipeline, _endpoint, options);
76+
_endpoint = OpenAIClient.GetEndpoint(options);
77+
_messageSubClient = new(_pipeline, options);
78+
_runSubClient = new(_pipeline, options);
79+
_threadSubClient = new(_pipeline, options);
7680
}
7781

7882
/// <summary> Creates a new assistant. </summary>

src/Custom/Assistants/Internal/InternalAssistantMessageClient.cs

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,42 +18,46 @@ namespace OpenAI.Assistants;
1818
[CodeGenSuppress("DeleteMessage", typeof(string), typeof(string))]
1919
internal partial class InternalAssistantMessageClient
2020
{
21-
/// <summary>
22-
/// Initializes a new instance of <see cref="InternalAssistantMessageClient"/> that will use an API key when authenticating.
23-
/// </summary>
24-
/// <param name="credential"> The API key used to authenticate with the service endpoint. </param>
25-
/// <param name="options"> Additional options to customize the client. </param>
26-
/// <exception cref="ArgumentNullException"> The provided <paramref name="credential"/> was null. </exception>
27-
public InternalAssistantMessageClient(ApiKeyCredential credential, OpenAIClientOptions options = default)
28-
: this(
29-
OpenAIClient.CreatePipeline(OpenAIClient.GetApiKey(credential, requireExplicitCredential: true), options),
30-
OpenAIClient.GetEndpoint(options),
31-
options)
32-
{ }
21+
// CUSTOM:
22+
// - Used a custom pipeline.
23+
// - Demoted the endpoint parameter to be a property in the options class.
24+
/// <summary> Initializes a new instance of <see cref="InternalAssistantMessageClient">. </summary>
25+
/// <param name="credential"> The API key to authenticate with the service. </param>
26+
/// <exception cref="ArgumentNullException"> <paramref name="credential"/> is null. </exception>
27+
public InternalAssistantMessageClient(ApiKeyCredential credential) : this(credential, new OpenAIClientOptions())
28+
{
29+
}
30+
31+
// CUSTOM:
32+
// - Used a custom pipeline.
33+
// - Demoted the endpoint parameter to be a property in the options class.
34+
/// <summary> Initializes a new instance of <see cref="InternalAssistantMessageClient">. </summary>
35+
/// <param name="credential"> The API key to authenticate with the service. </param>
36+
/// <param name="options"> The options to configure the client. </param>
37+
/// <exception cref="ArgumentNullException"> <paramref name="credential"/> is null. </exception>
38+
public InternalAssistantMessageClient(ApiKeyCredential credential, OpenAIClientOptions options)
39+
{
40+
Argument.AssertNotNull(credential, nameof(credential));
41+
options ??= new OpenAIClientOptions();
3342

34-
/// <summary>
35-
/// Initializes a new instance of <see cref="InternalAssistantMessageClient"/> that will use an API key from the OPENAI_API_KEY
36-
/// environment variable when authenticating.
37-
/// </summary>
38-
/// <remarks>
39-
/// To provide an explicit credential instead of using the environment variable, use an alternate constructor like
40-
/// <see cref="InternalAssistantMessageClient(ApiKeyCredential,OpenAIClientOptions)"/>.
41-
/// </remarks>
42-
/// <param name="options"> Additional options to customize the client. </param>
43-
/// <exception cref="InvalidOperationException"> The OPENAI_API_KEY environment variable was not found. </exception>
44-
public InternalAssistantMessageClient(OpenAIClientOptions options = default)
45-
: this(
46-
OpenAIClient.CreatePipeline(OpenAIClient.GetApiKey(), options),
47-
OpenAIClient.GetEndpoint(options),
48-
options)
49-
{ }
43+
_pipeline = OpenAIClient.CreatePipeline(credential, options);
44+
_endpoint = OpenAIClient.GetEndpoint(options);
45+
}
5046

51-
/// <summary> Initializes a new instance of <see cref="InternalAssistantMessageClient"/>. </summary>
52-
/// <param name="pipeline"> The HTTP pipeline for sending and receiving REST requests and responses. </param>
53-
/// <param name="endpoint"> OpenAI Endpoint. </param>
54-
protected internal InternalAssistantMessageClient(ClientPipeline pipeline, Uri endpoint, OpenAIClientOptions options)
47+
// CUSTOM:
48+
// - Used a custom pipeline.
49+
// - Demoted the endpoint parameter to be a property in the options class.
50+
// - Made protected.
51+
/// <summary> Initializes a new instance of <see cref="InternalAssistantMessageClient">. </summary>
52+
/// <param name="pipeline"> The HTTP pipeline to send and receive REST requests and responses. </param>
53+
/// <param name="options"> The options to configure the client. </param>
54+
/// <exception cref="ArgumentNullException"> <paramref name="pipeline"/> is null. </exception>
55+
protected internal InternalAssistantMessageClient(ClientPipeline pipeline, OpenAIClientOptions options)
5556
{
57+
Argument.AssertNotNull(pipeline, nameof(pipeline));
58+
options ??= new OpenAIClientOptions();
59+
5660
_pipeline = pipeline;
57-
_endpoint = endpoint;
61+
_endpoint = OpenAIClient.GetEndpoint(options);
5862
}
5963
}

0 commit comments

Comments
 (0)