From 1d33c048425ea4a14f505fd115d5b2e475523142 Mon Sep 17 00:00:00 2001 From: Chad Date: Wed, 6 Dec 2023 19:03:59 -0600 Subject: [PATCH 1/4] Added missing ContentType image_file and associated model. --- OpenAI-DotNet/Common/ContentType.cs | 4 +++- OpenAI-DotNet/Common/ImageFile.cs | 18 ++++++++++++++++++ OpenAI-DotNet/Threads/Content.cs | 6 ++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 OpenAI-DotNet/Common/ImageFile.cs diff --git a/OpenAI-DotNet/Common/ContentType.cs b/OpenAI-DotNet/Common/ContentType.cs index 35981cc3..f00e3c02 100644 --- a/OpenAI-DotNet/Common/ContentType.cs +++ b/OpenAI-DotNet/Common/ContentType.cs @@ -7,6 +7,8 @@ public enum ContentType [EnumMember(Value = "text")] Text, [EnumMember(Value = "image_url")] - ImageUrl + ImageUrl, + [EnumMember(Value = "image_file")] + ImageFile } } \ No newline at end of file diff --git a/OpenAI-DotNet/Common/ImageFile.cs b/OpenAI-DotNet/Common/ImageFile.cs new file mode 100644 index 00000000..cd1945fb --- /dev/null +++ b/OpenAI-DotNet/Common/ImageFile.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace OpenAI +{ + public sealed class ImageFile + { + [JsonConstructor] + public ImageFile(string fileId) + { + FileId = fileId; + } + + [JsonInclude] + [JsonPropertyName("file_id")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public string FileId { get; private set; } + } +} \ No newline at end of file diff --git a/OpenAI-DotNet/Threads/Content.cs b/OpenAI-DotNet/Threads/Content.cs index 85002bed..92fbeb3e 100644 --- a/OpenAI-DotNet/Threads/Content.cs +++ b/OpenAI-DotNet/Threads/Content.cs @@ -21,11 +21,17 @@ public sealed class Content [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public ImageUrl ImageUrl { get; private set; } + [JsonInclude] + [JsonPropertyName("image_file")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] + public ImageFile ImageFile { get; private set; } + public override string ToString() => Type switch { ContentType.Text => Text.Value, ContentType.ImageUrl => ImageUrl.Url, + ContentType.ImageFile => ImageFile.FileId, _ => throw new ArgumentOutOfRangeException() }; } From 5e1821413e9affab8affd5f6a58196821aa98954 Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Wed, 6 Dec 2023 20:52:18 -0500 Subject: [PATCH 2/4] Version 7.4.2 - Fixed missing Threads.Message.Content.ImageFile property. - Marked OpenAI.Completions Obsolete --- .../TestFixture_02_Completions.cs | 7 +- OpenAI-DotNet/Common/ImageFile.cs | 6 -- OpenAI-DotNet/Completions/Choice.cs | 4 +- .../Completions/CompletionRequest.cs | 1 + .../Completions/CompletionResponse.cs | 1 + .../Completions/CompletionsEndpoint.cs | 1 + OpenAI-DotNet/Completions/LogProbabilities.cs | 4 +- OpenAI-DotNet/OpenAI-DotNet.csproj | 5 +- OpenAI-DotNet/OpenAIClient.cs | 43 ++++++------ OpenAI-DotNet/Threads/Content.cs | 6 -- README.md | 68 ++++++++++--------- 11 files changed, 75 insertions(+), 71 deletions(-) diff --git a/OpenAI-DotNet-Tests/TestFixture_02_Completions.cs b/OpenAI-DotNet-Tests/TestFixture_02_Completions.cs index 1182e74c..4b9f54ef 100644 --- a/OpenAI-DotNet-Tests/TestFixture_02_Completions.cs +++ b/OpenAI-DotNet-Tests/TestFixture_02_Completions.cs @@ -8,11 +8,12 @@ namespace OpenAI.Tests { + [Obsolete("Deprecated")] internal class TestFixture_02_Completions : AbstractTestFixture { private const string CompletionPrompts = "One Two Three Four Five Six Seven Eight Nine One Two Three Four Five Six Seven Eight"; - [Test] + //[Test] public async Task Test_01_GetBasicCompletion() { Assert.IsNotNull(OpenAIClient.CompletionsEndpoint); @@ -29,7 +30,7 @@ public async Task Test_01_GetBasicCompletion() Console.WriteLine(result); } - [Test] + //[Test] public async Task Test_02_GetStreamingCompletion() { Assert.IsNotNull(OpenAIClient.CompletionsEndpoint); @@ -47,7 +48,7 @@ await OpenAIClient.CompletionsEndpoint.StreamCompletionAsync(result => Console.WriteLine(allCompletions.FirstOrDefault()); } - [Test] + //[Test] public async Task Test_03_GetStreamingEnumerableCompletion() { Assert.IsNotNull(OpenAIClient.CompletionsEndpoint); diff --git a/OpenAI-DotNet/Common/ImageFile.cs b/OpenAI-DotNet/Common/ImageFile.cs index cd1945fb..70cb8021 100644 --- a/OpenAI-DotNet/Common/ImageFile.cs +++ b/OpenAI-DotNet/Common/ImageFile.cs @@ -4,12 +4,6 @@ namespace OpenAI { public sealed class ImageFile { - [JsonConstructor] - public ImageFile(string fileId) - { - FileId = fileId; - } - [JsonInclude] [JsonPropertyName("file_id")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] diff --git a/OpenAI-DotNet/Completions/Choice.cs b/OpenAI-DotNet/Completions/Choice.cs index e5081326..e00e2314 100644 --- a/OpenAI-DotNet/Completions/Choice.cs +++ b/OpenAI-DotNet/Completions/Choice.cs @@ -1,10 +1,12 @@ -using System.Text.Json.Serialization; +using System; +using System.Text.Json.Serialization; namespace OpenAI.Completions { /// /// Represents a completion choice returned by the . /// + [Obsolete("Deprecated")] public sealed class Choice { /// diff --git a/OpenAI-DotNet/Completions/CompletionRequest.cs b/OpenAI-DotNet/Completions/CompletionRequest.cs index d92bb43a..361dee1c 100644 --- a/OpenAI-DotNet/Completions/CompletionRequest.cs +++ b/OpenAI-DotNet/Completions/CompletionRequest.cs @@ -10,6 +10,7 @@ namespace OpenAI.Completions /// the OpenAI docs, /// although some have been renames or expanded into single/multiple properties for ease of use. /// + [Obsolete("Deprecated")] public sealed class CompletionRequest { [JsonPropertyName("model")] diff --git a/OpenAI-DotNet/Completions/CompletionResponse.cs b/OpenAI-DotNet/Completions/CompletionResponse.cs index 4bfad93a..5679e289 100644 --- a/OpenAI-DotNet/Completions/CompletionResponse.cs +++ b/OpenAI-DotNet/Completions/CompletionResponse.cs @@ -8,6 +8,7 @@ namespace OpenAI.Completions /// /// Represents a result from calling the . /// + [Obsolete("Deprecated")] public sealed class CompletionResponse : BaseResponse { public CompletionResponse() { } diff --git a/OpenAI-DotNet/Completions/CompletionsEndpoint.cs b/OpenAI-DotNet/Completions/CompletionsEndpoint.cs index a4c4ad73..40e12c61 100644 --- a/OpenAI-DotNet/Completions/CompletionsEndpoint.cs +++ b/OpenAI-DotNet/Completions/CompletionsEndpoint.cs @@ -19,6 +19,7 @@ namespace OpenAI.Completions /// (see the prompt library for inspiration).
/// /// + [Obsolete("Deprecated")] public sealed class CompletionsEndpoint : BaseEndPoint { /// diff --git a/OpenAI-DotNet/Completions/LogProbabilities.cs b/OpenAI-DotNet/Completions/LogProbabilities.cs index f29a86fc..08e00cfd 100644 --- a/OpenAI-DotNet/Completions/LogProbabilities.cs +++ b/OpenAI-DotNet/Completions/LogProbabilities.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Text.Json.Serialization; namespace OpenAI.Completions @@ -6,6 +7,7 @@ namespace OpenAI.Completions /// /// Object belonging to a /// + [Obsolete("Deprecated")] public sealed class LogProbabilities { [JsonInclude] diff --git a/OpenAI-DotNet/OpenAI-DotNet.csproj b/OpenAI-DotNet/OpenAI-DotNet.csproj index a7db3aa3..1689369f 100644 --- a/OpenAI-DotNet/OpenAI-DotNet.csproj +++ b/OpenAI-DotNet/OpenAI-DotNet.csproj @@ -18,8 +18,11 @@ More context [on Roger Pincombe's blog](https://rogerpincombe.com/openai-dotnet- https://github.com/RageAgainstThePixel/OpenAI-DotNet OpenAI, AI, ML, API, gpt-4, gpt-3.5-tubo, gpt-3, chatGPT, chat-gpt, gpt-2, gpt, dall-e-2, dall-e-3 OpenAI-DotNet - 7.4.1 + 7.4.2 +Version 7.4.2 +- Fixed missing Threads.Message.Content.ImageFile property. +- Marked OpenAI.Completions Obsolete Version 7.4.1 - Fixed AssistantExtension.UploadFileAsync spelling error with file purpose. Version 7.4.0 diff --git a/OpenAI-DotNet/OpenAIClient.cs b/OpenAI-DotNet/OpenAIClient.cs index 6254d7cf..29aea40b 100644 --- a/OpenAI-DotNet/OpenAIClient.cs +++ b/OpenAI-DotNet/OpenAIClient.cs @@ -50,11 +50,7 @@ public OpenAIClient(OpenAIAuthentication openAIAuthentication = null, OpenAIClie Client = SetupClient(client); ModelsEndpoint = new ModelsEndpoint(this); - CompletionsEndpoint = new CompletionsEndpoint(this); ChatEndpoint = new ChatEndpoint(this); -#pragma warning disable CS0618 // Type or member is obsolete - EditsEndpoint = new EditsEndpoint(this); -#pragma warning restore CS0618 // Type or member is obsolete ImagesEndPoint = new ImagesEndpoint(this); EmbeddingsEndpoint = new EmbeddingsEndpoint(this); AudioEndpoint = new AudioEndpoint(this); @@ -63,6 +59,10 @@ public OpenAIClient(OpenAIAuthentication openAIAuthentication = null, OpenAIClie ModerationsEndpoint = new ModerationsEndpoint(this); ThreadsEndpoint = new ThreadsEndpoint(this); AssistantsEndpoint = new AssistantsEndpoint(this); +#pragma warning disable CS0618 // Type or member is obsolete + CompletionsEndpoint = new CompletionsEndpoint(this); + EditsEndpoint = new EditsEndpoint(this); +#pragma warning restore CS0618 // Type or member is obsolete } private HttpClient SetupClient(HttpClient client = null) @@ -135,29 +135,12 @@ private HttpClient SetupClient(HttpClient client = null) /// public ModelsEndpoint ModelsEndpoint { get; } - /// - /// Text generation is the core function of the API. You give the API a prompt, and it generates a completion. - /// The way you “program” the API to do a task is by simply describing the task in plain english or providing - /// a few written examples. This simple approach works for a wide range of use cases, including summarization, - /// translation, grammar correction, question answering, chatbots, composing emails, and much more - /// (see the prompt library for inspiration).
- /// - ///
- public CompletionsEndpoint CompletionsEndpoint { get; } - /// /// Given a chat conversation, the model will return a chat completion response.
/// ///
public ChatEndpoint ChatEndpoint { get; } - /// - /// Given a prompt and an instruction, the model will return an edited version of the prompt.
- /// - ///
- [Obsolete("Deprecated")] - public EditsEndpoint EditsEndpoint { get; } - /// /// Given a prompt and/or an input image, the model will generate a new image.
/// @@ -207,5 +190,23 @@ private HttpClient SetupClient(HttpClient client = null) /// ///
public ThreadsEndpoint ThreadsEndpoint { get; } + + /// + /// Text generation is the core function of the API. You give the API a prompt, and it generates a completion. + /// The way you “program” the API to do a task is by simply describing the task in plain english or providing + /// a few written examples. This simple approach works for a wide range of use cases, including summarization, + /// translation, grammar correction, question answering, chatbots, composing emails, and much more + /// (see the prompt library for inspiration).
+ /// + ///
+ [Obsolete("Deprecated")] + public CompletionsEndpoint CompletionsEndpoint { get; } + + /// + /// Given a prompt and an instruction, the model will return an edited version of the prompt.
+ /// + ///
+ [Obsolete("Deprecated")] + public EditsEndpoint EditsEndpoint { get; } } } \ No newline at end of file diff --git a/OpenAI-DotNet/Threads/Content.cs b/OpenAI-DotNet/Threads/Content.cs index 92fbeb3e..e1db35f8 100644 --- a/OpenAI-DotNet/Threads/Content.cs +++ b/OpenAI-DotNet/Threads/Content.cs @@ -16,11 +16,6 @@ public sealed class Content [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] public TextContent Text { get; private set; } - [JsonInclude] - [JsonPropertyName("image_url")] - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] - public ImageUrl ImageUrl { get; private set; } - [JsonInclude] [JsonPropertyName("image_file")] [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] @@ -30,7 +25,6 @@ public override string ToString() => Type switch { ContentType.Text => Text.Value, - ContentType.ImageUrl => ImageUrl.Url, ContentType.ImageFile => ImageFile.FileId, _ => throw new ArgumentOutOfRangeException() }; diff --git a/README.md b/README.md index 305773ad..6f414894 100644 --- a/README.md +++ b/README.md @@ -109,10 +109,10 @@ Install-Package OpenAI-DotNet - [List Fine Tune Job Events](#list-fine-tune-job-events) :construction: - [Embeddings](#embeddings) - [Create Embedding](#create-embeddings) -- [Completions](#completions) :construction: - - [Streaming](#completion-streaming) :construction: - [Moderations](#moderations) - [Create Moderation](#create-moderation) +- ~~[Completions](#completions)~~ :warning: Deprecated + - ~~[Streaming](#completion-streaming)~~ :warning: Deprecated - ~~[Edits](#edits)~~ :warning: Deprecated - ~~[Create Edit](#create-edit)~~ :warning: Deprecated @@ -867,7 +867,7 @@ var messages = new List var chatRequest = new ChatRequest(messages); var response = await api.ChatEndpoint.StreamCompletionAsync(chatRequest, partialResponse => { - Console.Write(choice.Delta.ToString()); + Console.Write(partialResponse.FirstChoice.Delta.ToString()); }); var choice = response.FirstChoice; Console.WriteLine($"[{choice.Index}] {choice.Message.Role}: {choice.Message} | Finish Reason: {choice.FinishReason}"); @@ -1283,8 +1283,38 @@ var response = await api.EmbeddingsEndpoint.CreateEmbeddingAsync("The food was d Console.WriteLine(response); ``` +### [Moderations](https://platform.openai.com/docs/api-reference/moderations) + +Given a input text, outputs if the model classifies it as violating OpenAI's content policy. + +Related guide: [Moderations](https://platform.openai.com/docs/guides/moderation) + +The Moderations API can be accessed via `OpenAIClient.ModerationsEndpoint` + +#### [Create Moderation](https://platform.openai.com/docs/api-reference/moderations/create) + +Classifies if text violates OpenAI's Content Policy. + +```csharp +var api = new OpenAIClient(); +var isViolation = await api.ModerationsEndpoint.GetModerationAsync("I want to kill them."); +Assert.IsTrue(isViolation); +``` + +Additionally you can also get the scores of a given input. + +```csharp +var response = await OpenAIClient.ModerationsEndpoint.CreateModerationAsync(new ModerationsRequest("I love you")); +Assert.IsNotNull(response); +Console.WriteLine(response.Results?[0]?.Scores?.ToString()); +``` + +--- + ### [Completions](https://platform.openai.com/docs/api-reference/completions) +> :warning: Deprecated, and soon to be removed. + Given a prompt, the model will return one or more predicted completions, and can also return the probabilities of alternative tokens at each position. The Completions API is accessed via `OpenAIClient.CompletionsEndpoint` @@ -1299,6 +1329,8 @@ Console.WriteLine(response); #### Completion Streaming +> :warning: Deprecated, and soon to be removed. + Streaming allows you to get results are they are generated, which can help your application feel more responsive, especially on slow models like Davinci. ```csharp @@ -1323,37 +1355,9 @@ await foreach (var partialResponse in api.CompletionsEndpoint.StreamCompletionEn } ``` -### [Moderations](https://platform.openai.com/docs/api-reference/moderations) - -Given a input text, outputs if the model classifies it as violating OpenAI's content policy. - -Related guide: [Moderations](https://platform.openai.com/docs/guides/moderation) - -The Moderations API can be accessed via `OpenAIClient.ModerationsEndpoint` - -#### [Create Moderation](https://platform.openai.com/docs/api-reference/moderations/create) - -Classifies if text violates OpenAI's Content Policy. - -```csharp -var api = new OpenAIClient(); -var isViolation = await api.ModerationsEndpoint.GetModerationAsync("I want to kill them."); -Assert.IsTrue(isViolation); -``` - -Additionally you can also get the scores of a given input. - -```csharp -var response = await OpenAIClient.ModerationsEndpoint.CreateModerationAsync(new ModerationsRequest("I love you")); -Assert.IsNotNull(response); -Console.WriteLine(response.Results?[0]?.Scores?.ToString()); -``` - ---- - ### [Edits](https://platform.openai.com/docs/api-reference/edits) -> Deprecated, and soon to be removed. +> :warning: Deprecated, and soon to be removed. Given a prompt and an instruction, the model will return an edited version of the prompt. From 98b776459eb58f4aa65995a436491c20d0a3b4b7 Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Wed, 6 Dec 2023 20:59:45 -0500 Subject: [PATCH 3/4] add missing extension from docs --- OpenAI-DotNet/Threads/ThreadExtensions.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/OpenAI-DotNet/Threads/ThreadExtensions.cs b/OpenAI-DotNet/Threads/ThreadExtensions.cs index 8d84470f..025197d9 100644 --- a/OpenAI-DotNet/Threads/ThreadExtensions.cs +++ b/OpenAI-DotNet/Threads/ThreadExtensions.cs @@ -224,6 +224,16 @@ public static async Task> ListRunsAsync(this ThreadRes public static async Task UpdateAsync(this RunResponse run, CancellationToken cancellationToken = default) => await run.Client.ThreadsEndpoint.RetrieveRunAsync(run.ThreadId, run.Id, cancellationToken).ConfigureAwait(false); + /// + /// Retrieves a run. + /// + /// The thread that was run. + /// The id of the run to retrieve. + /// Optional, . + /// . + public static async Task RetrieveRunAsync(this ThreadResponse thread, string runId, CancellationToken cancellationToken = default) + => await thread.Client.ThreadsEndpoint.RetrieveRunAsync(thread.Id, runId, cancellationToken); + /// /// Modifies a run. /// From 155bf5c3c77ef2e8c4e97e4b28d8e0be2dab102b Mon Sep 17 00:00:00 2001 From: Stephen Hodgson Date: Wed, 6 Dec 2023 21:43:16 -0500 Subject: [PATCH 4/4] fixed up some tests --- .../TestFixture_11_Assistants.cs | 40 ++++++++++++------- OpenAI-DotNet-Tests/TestFixture_12_Threads.cs | 12 +++--- .../Assistants/AssistantExtensions.cs | 3 +- OpenAI-DotNet/Threads/ThreadExtensions.cs | 2 +- 4 files changed, 36 insertions(+), 21 deletions(-) diff --git a/OpenAI-DotNet-Tests/TestFixture_11_Assistants.cs b/OpenAI-DotNet-Tests/TestFixture_11_Assistants.cs index 3fde5db6..28bed9aa 100644 --- a/OpenAI-DotNet-Tests/TestFixture_11_Assistants.cs +++ b/OpenAI-DotNet-Tests/TestFixture_11_Assistants.cs @@ -56,9 +56,9 @@ public async Task Test_02_ListAssistants() foreach (var assistant in assistantsList.Items) { - var retrieved = OpenAIClient.AssistantsEndpoint.RetrieveAssistantAsync(assistant); + var retrieved = await OpenAIClient.AssistantsEndpoint.RetrieveAssistantAsync(assistant); Assert.IsNotNull(retrieved); - Console.WriteLine($"{assistant} -> {assistant.CreatedAt}"); + Console.WriteLine($"{retrieved} -> {retrieved.CreatedAt}"); } } @@ -90,8 +90,9 @@ public async Task Test_04_01_UploadAssistantFile() const string testFilePath = "assistant_test_2.txt"; await File.WriteAllTextAsync(testFilePath, "Knowledge is power!"); Assert.IsTrue(File.Exists(testFilePath)); - var file = testAssistant.UploadFileAsync(testFilePath); + var file = await testAssistant.UploadFileAsync(testFilePath); Assert.IsNotNull(file); + Console.WriteLine($"uploaded -> {file.Id}"); } [Test] @@ -102,6 +103,7 @@ public async Task Test_04_02_ListAssistantFiles() var filesList = await testAssistant.ListFilesAsync(); Assert.IsNotNull(filesList); Assert.IsNotEmpty(filesList.Items); + Assert.IsTrue(filesList.Items.Count == 2); foreach (var file in filesList.Items) { @@ -120,25 +122,35 @@ public async Task Test_04_02_ListAssistantFiles() } [Test] - public async Task Test_04_03_DeleteAssistantFiles() + public async Task Test_04_03_RemoveAssistantFile() { Assert.IsNotNull(testAssistant); Assert.IsNotNull(OpenAIClient.AssistantsEndpoint); var filesList = await testAssistant.ListFilesAsync(); Assert.IsNotNull(filesList); Assert.IsNotEmpty(filesList.Items); + Assert.IsTrue(filesList.Items.Count == 2); + var assistantFile = filesList.Items[0]; + Assert.IsNotNull(assistantFile); + var isRemoved = await testAssistant.RemoveFileAsync(assistantFile); + Assert.IsTrue(isRemoved); + var isDeleted = await OpenAIClient.FilesEndpoint.DeleteFileAsync(assistantFile); + Assert.IsTrue(isDeleted); + } - foreach (var file in filesList.Items) - { - Assert.IsNotNull(file); - var isDeleted = await testAssistant.DeleteFileAsync(file); - Assert.IsTrue(isDeleted); - Console.WriteLine($"Deleted {file.Id}"); - } - - filesList = await testAssistant.ListFilesAsync(); + [Test] + public async Task Test_04_04_DeleteAssistantFiles() + { + Assert.IsNotNull(testAssistant); + Assert.IsNotNull(OpenAIClient.AssistantsEndpoint); + var filesList = await testAssistant.ListFilesAsync(); Assert.IsNotNull(filesList); - Assert.IsEmpty(filesList.Items); + Assert.IsNotEmpty(filesList.Items); + Assert.IsTrue(filesList.Items.Count == 1); + var assistantFile = filesList.Items[0]; + Assert.IsNotNull(assistantFile); + var isDeleted = await testAssistant.DeleteFileAsync(assistantFile); + Assert.IsTrue(isDeleted); } [Test] diff --git a/OpenAI-DotNet-Tests/TestFixture_12_Threads.cs b/OpenAI-DotNet-Tests/TestFixture_12_Threads.cs index e7823a47..43c89c8d 100644 --- a/OpenAI-DotNet-Tests/TestFixture_12_Threads.cs +++ b/OpenAI-DotNet-Tests/TestFixture_12_Threads.cs @@ -207,8 +207,6 @@ public async Task Test_05_DeleteThread() Console.WriteLine($"Deleted thread {testThread.Id}"); } - - [Test] public async Task Test_06_01_CreateRun() { @@ -225,12 +223,13 @@ public async Task Test_06_01_CreateRun() try { - var message = thread.CreateMessageAsync("I need to solve the equation `3x + 11 = 14`. Can you help me?"); + var message = await thread.CreateMessageAsync("I need to solve the equation `3x + 11 = 14`. Can you help me?"); Assert.NotNull(message); var run = await thread.CreateRunAsync(assistant); Assert.IsNotNull(run); - var threadRun = thread.CreateRunAsync(); - Assert.NotNull(threadRun); + run = await run.WaitForStatusChangeAsync(); + Assert.IsNotNull(run); + Assert.IsTrue(run.Status == RunStatus.Completed); } finally { @@ -269,6 +268,9 @@ public async Task Test_06_03_ListRunsAndSteps() Assert.IsNotNull(run.Client); var retrievedRun = await run.UpdateAsync(); Assert.IsNotNull(retrievedRun); + var threadRun = await testThread.RetrieveRunAsync(run.Id); + Assert.IsNotNull(threadRun); + Assert.IsTrue(retrievedRun.Id == threadRun.Id); Console.WriteLine($"[{retrievedRun.Id}] {retrievedRun.Status} | {retrievedRun.CreatedAt}"); } } diff --git a/OpenAI-DotNet/Assistants/AssistantExtensions.cs b/OpenAI-DotNet/Assistants/AssistantExtensions.cs index 09e70ed8..39e55299 100644 --- a/OpenAI-DotNet/Assistants/AssistantExtensions.cs +++ b/OpenAI-DotNet/Assistants/AssistantExtensions.cs @@ -150,7 +150,8 @@ public static async Task DeleteFileAsync(this AssistantFileResponse file, public static async Task DeleteFileAsync(this AssistantResponse assistant, string fileId, CancellationToken cancellationToken = default) { var isRemoved = await assistant.Client.AssistantsEndpoint.RemoveFileAsync(assistant.Id, fileId, cancellationToken).ConfigureAwait(false); - return isRemoved && await assistant.Client.FilesEndpoint.DeleteFileAsync(fileId, cancellationToken).ConfigureAwait(false); + if (!isRemoved) { return false; } + return await assistant.Client.FilesEndpoint.DeleteFileAsync(fileId, cancellationToken).ConfigureAwait(false); } #endregion Files diff --git a/OpenAI-DotNet/Threads/ThreadExtensions.cs b/OpenAI-DotNet/Threads/ThreadExtensions.cs index 025197d9..770254ae 100644 --- a/OpenAI-DotNet/Threads/ThreadExtensions.cs +++ b/OpenAI-DotNet/Threads/ThreadExtensions.cs @@ -232,7 +232,7 @@ public static async Task UpdateAsync(this RunResponse run, Cancella /// Optional, . /// . public static async Task RetrieveRunAsync(this ThreadResponse thread, string runId, CancellationToken cancellationToken = default) - => await thread.Client.ThreadsEndpoint.RetrieveRunAsync(thread.Id, runId, cancellationToken); + => await thread.Client.ThreadsEndpoint.RetrieveRunAsync(thread.Id, runId, cancellationToken).ConfigureAwait(false); /// /// Modifies a run.