From 01608a2aab7fdf0ecbde2d0ae9417ad08ffb5c42 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Mon, 5 Aug 2024 14:00:15 -0700 Subject: [PATCH 01/14] initial checkin of polling-based LROs --- src/Custom/Batch/BatchClient.Protocol.cs | 90 +-- src/Custom/Batch/BatchClient.cs | 1 - .../FineTuning/FineTuningClient.Protocol.cs | 205 +----- .../VectorStoreClient.Convenience.cs | 77 +-- .../VectorStoreClient.Protocol.cs | 189 +----- src/Custom/VectorStores/VectorStoreClient.cs | 303 +-------- src/Generated/BatchClient.cs | 17 - src/Generated/FineTuningClient.cs | 83 --- src/Generated/VectorStoreClient.cs | 76 --- src/OpenAI.csproj | 2 +- .../BatchOperation.Protocol.cs | 153 +++++ src/To.Be.Generated/BatchOperationToken.cs | 90 +++ ...BatchOperationUpdateEnumerator.Protocol.cs | 165 +++++ .../FineTuningOperation.Protocol.cs | 344 ++++++++++ .../FineTuningOperationToken.cs | 91 +++ ...uningOperationUpdateEnumerator.Protocol.cs | 170 +++++ .../Internal/PollingInterval.cs | 29 + src/To.Be.Generated/RunOperation.Protocol.cs | 639 ++++++++++++++++++ src/To.Be.Generated/RunOperation.cs | 392 +++++++++++ src/To.Be.Generated/RunOperationToken.cs | 102 +++ .../RunOperationUpdateEnumerator.Protocol.cs | 175 +++++ .../RunOperationUpdateEnumerator.cs | 54 ++ src/To.Be.Generated/StreamingRunOperation.cs | 280 ++++++++ .../StreamingRunOperationUpdateEnumerator.cs | 145 ++++ .../VectorStoreFileBatchOperation.Protocol.cs | 343 ++++++++++ .../VectorStoreFileBatchOperation.cs | 291 ++++++++ .../VectorStoreFileBatchOperationToken.cs | 101 +++ ...BatchOperationUpdateEnumerator.Protocol.cs | 175 +++++ ...StoreFileBatchOperationUpdateEnumerator.cs | 54 ++ tests/Assistants/VectorStoreTests.cs | 25 +- tests/Batch/BatchTests.cs | 18 +- tests/FineTuning/FineTuningTests.cs | 89 +++ tests/Utility/TestHelpers.cs | 2 + 33 files changed, 4051 insertions(+), 919 deletions(-) create mode 100644 src/To.Be.Generated/BatchOperation.Protocol.cs create mode 100644 src/To.Be.Generated/BatchOperationToken.cs create mode 100644 src/To.Be.Generated/BatchOperationUpdateEnumerator.Protocol.cs create mode 100644 src/To.Be.Generated/FineTuningOperation.Protocol.cs create mode 100644 src/To.Be.Generated/FineTuningOperationToken.cs create mode 100644 src/To.Be.Generated/FineTuningOperationUpdateEnumerator.Protocol.cs create mode 100644 src/To.Be.Generated/Internal/PollingInterval.cs create mode 100644 src/To.Be.Generated/RunOperation.Protocol.cs create mode 100644 src/To.Be.Generated/RunOperation.cs create mode 100644 src/To.Be.Generated/RunOperationToken.cs create mode 100644 src/To.Be.Generated/RunOperationUpdateEnumerator.Protocol.cs create mode 100644 src/To.Be.Generated/RunOperationUpdateEnumerator.cs create mode 100644 src/To.Be.Generated/StreamingRunOperation.cs create mode 100644 src/To.Be.Generated/StreamingRunOperationUpdateEnumerator.cs create mode 100644 src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs create mode 100644 src/To.Be.Generated/VectorStoreFileBatchOperation.cs create mode 100644 src/To.Be.Generated/VectorStoreFileBatchOperationToken.cs create mode 100644 src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.Protocol.cs create mode 100644 src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.cs create mode 100644 tests/FineTuning/FineTuningTests.cs diff --git a/src/Custom/Batch/BatchClient.Protocol.cs b/src/Custom/Batch/BatchClient.Protocol.cs index 11cc1097..321502ee 100644 --- a/src/Custom/Batch/BatchClient.Protocol.cs +++ b/src/Custom/Batch/BatchClient.Protocol.cs @@ -1,42 +1,58 @@ using System; using System.ClientModel; using System.ClientModel.Primitives; +using System.Text.Json; using System.Threading.Tasks; namespace OpenAI.Batch; public partial class BatchClient { - /// - /// [Protocol Method] Creates and executes a batch from an uploaded file of requests - /// - /// The content to send as the body of the request. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task CreateBatchAsync(BinaryContent content, RequestOptions options = null) + public virtual async Task CreateBatchAsync( + ReturnWhen returnWhen, + BinaryContent content, RequestOptions options = null) { Argument.AssertNotNull(content, nameof(content)); using PipelineMessage message = CreateCreateBatchRequest(content, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + + PipelineResponse response = await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string batchId = doc.RootElement.GetProperty("id"u8).GetString(); + string status = doc.RootElement.GetProperty("status"u8).GetString(); + + BatchOperation operation = new BatchOperation(_pipeline, _endpoint, batchId, status, response); + if (returnWhen == ReturnWhen.Started) + { + return operation; + } + + await operation.WaitForCompletionAsync(options?.CancellationToken ?? default).ConfigureAwait(false); + return operation; } - /// - /// [Protocol Method] Creates and executes a batch from an uploaded file of requests - /// - /// The content to send as the body of the request. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult CreateBatch(BinaryContent content, RequestOptions options = null) + public virtual BatchOperation CreateBatch( + ReturnWhen returnWhen, + BinaryContent content, RequestOptions options = null) { Argument.AssertNotNull(content, nameof(content)); using PipelineMessage message = CreateCreateBatchRequest(content, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + PipelineResponse response = _pipeline.ProcessMessage(message, options); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string batchId = doc.RootElement.GetProperty("id"u8).GetString(); + string status = doc.RootElement.GetProperty("status"u8).GetString(); + + BatchOperation operation = new BatchOperation(_pipeline, _endpoint, batchId, status, response); + if (returnWhen == ReturnWhen.Started) + { + return operation; + } + + operation.WaitForCompletion(options?.CancellationToken ?? default); + return operation; } /// @@ -100,38 +116,4 @@ public virtual ClientResult GetBatch(string batchId, RequestOptions options) using PipelineMessage message = CreateRetrieveBatchRequest(batchId, options); return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - - /// - /// [Protocol Method] Cancels an in-progress batch. - /// - /// The ID of the batch to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task CancelBatchAsync(string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateCancelBatchRequest(batchId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Cancels an in-progress batch. - /// - /// The ID of the batch to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult CancelBatch(string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateCancelBatchRequest(batchId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } } diff --git a/src/Custom/Batch/BatchClient.cs b/src/Custom/Batch/BatchClient.cs index adce1b0d..a5c75e9a 100644 --- a/src/Custom/Batch/BatchClient.cs +++ b/src/Custom/Batch/BatchClient.cs @@ -2,7 +2,6 @@ using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; -using System.Threading.Tasks; namespace OpenAI.Batch; diff --git a/src/Custom/FineTuning/FineTuningClient.Protocol.cs b/src/Custom/FineTuning/FineTuningClient.Protocol.cs index 2483478d..5c97e02d 100644 --- a/src/Custom/FineTuning/FineTuningClient.Protocol.cs +++ b/src/Custom/FineTuning/FineTuningClient.Protocol.cs @@ -1,6 +1,7 @@ using System; using System.ClientModel; using System.ClientModel.Primitives; +using System.Text.Json; using System.Threading.Tasks; namespace OpenAI.FineTuning; @@ -34,12 +35,27 @@ public partial class FineTuningClient /// is null. /// Service returned a non-success status code. /// The response returned from the service. - public virtual async Task CreateJobAsync(BinaryContent content, RequestOptions options = null) + public virtual async Task CreateJobAsync( + ReturnWhen returnWhen, + BinaryContent content, RequestOptions options = null) { Argument.AssertNotNull(content, nameof(content)); using PipelineMessage message = CreateCreateFineTuningJobRequest(content, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + PipelineResponse response = await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string jobId = doc.RootElement.GetProperty("id"u8).GetString(); + string status = doc.RootElement.GetProperty("status"u8).GetString(); + + FineTuningOperation operation = new FineTuningOperation(_pipeline, _endpoint, jobId, status, response); + if (returnWhen == ReturnWhen.Started) + { + return operation; + } + + await operation.WaitForCompletionAsync(options?.CancellationToken ?? default).ConfigureAwait(false); + return operation; } // CUSTOM: @@ -57,12 +73,27 @@ public virtual async Task CreateJobAsync(BinaryContent content, Re /// is null. /// Service returned a non-success status code. /// The response returned from the service. - public virtual ClientResult CreateJob(BinaryContent content, RequestOptions options = null) + public virtual FineTuningOperation CreateJob( + ReturnWhen returnWhen, + BinaryContent content, RequestOptions options = null) { Argument.AssertNotNull(content, nameof(content)); using PipelineMessage message = CreateCreateFineTuningJobRequest(content, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + PipelineResponse response = _pipeline.ProcessMessage(message, options); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string jobId = doc.RootElement.GetProperty("id"u8).GetString(); + string status = doc.RootElement.GetProperty("status"u8).GetString(); + + FineTuningOperation operation = new FineTuningOperation(_pipeline, _endpoint, jobId, status, response); + if (returnWhen == ReturnWhen.Started) + { + return operation; + } + + operation.WaitForCompletion(options?.CancellationToken ?? default); + return operation; } // CUSTOM: @@ -98,170 +129,4 @@ public virtual ClientResult GetJobs(string after, int? limit, RequestOptions opt using PipelineMessage message = CreateGetPaginatedFineTuningJobsRequest(after, limit, options); return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - - // CUSTOM: - // - Renamed. - // - Edited doc comment. - /// - /// [Protocol Method] Get info about a fine-tuning job. - /// - /// [Learn more about fine-tuning](/docs/guides/fine-tuning) - /// - /// The ID of the fine-tuning job. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task GetJobAsync(string jobId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateRetrieveFineTuningJobRequest(jobId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - // CUSTOM: - // - Renamed. - // - Edited doc comment. - /// - /// [Protocol Method] Get info about a fine-tuning job. - /// - /// [Learn more about fine-tuning](/docs/guides/fine-tuning) - /// - /// The ID of the fine-tuning job. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult GetJob(string jobId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateRetrieveFineTuningJobRequest(jobId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - // CUSTOM: - // - Renamed. - // - Edited doc comment. - /// - /// [Protocol Method] Immediately cancel a fine-tune job. - /// - /// The ID of the fine-tuning job to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task CancelJobAsync(string jobId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateCancelFineTuningJobRequest(jobId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - // CUSTOM: - // - Renamed. - // - Edited doc comment. - /// - /// [Protocol Method] Immediately cancel a fine-tune job. - /// - /// The ID of the fine-tuning job to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult CancelJob(string jobId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateCancelFineTuningJobRequest(jobId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - // CUSTOM: - // - Renamed. - // - Edited doc comment. - /// - /// [Protocol Method] Get status updates for a fine-tuning job. - /// - /// The ID of the fine-tuning job to get events for. - /// Identifier for the last event from the previous pagination request. - /// Number of events to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task GetJobEventsAsync(string jobId, string after, int? limit, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateGetFineTuningEventsRequest(jobId, after, limit, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - // CUSTOM: - // - Renamed. - // - Edited doc comment. - /// - /// [Protocol Method] Get status updates for a fine-tuning job. - /// - /// The ID of the fine-tuning job to get events for. - /// Identifier for the last event from the previous pagination request. - /// Number of events to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult GetJobEvents(string jobId, string after, int? limit, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateGetFineTuningEventsRequest(jobId, after, limit, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - /// - /// [Protocol Method] List the checkpoints for a fine-tuning job. - /// - /// The ID of the fine-tuning job to get checkpoints for. - /// Identifier for the last checkpoint ID from the previous pagination request. - /// Number of checkpoints to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task GetJobCheckpointsAsync(string fineTuningJobId, string after, int? limit, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(fineTuningJobId, nameof(fineTuningJobId)); - - using PipelineMessage message = CreateGetFineTuningJobCheckpointsRequest(fineTuningJobId, after, limit, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] List the checkpoints for a fine-tuning job. - /// - /// The ID of the fine-tuning job to get checkpoints for. - /// Identifier for the last checkpoint ID from the previous pagination request. - /// Number of checkpoints to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult GetJobCheckpoints(string fineTuningJobId, string after, int? limit, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(fineTuningJobId, nameof(fineTuningJobId)); - - using PipelineMessage message = CreateGetFineTuningJobCheckpointsRequest(fineTuningJobId, after, limit, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } } diff --git a/src/Custom/VectorStores/VectorStoreClient.Convenience.cs b/src/Custom/VectorStores/VectorStoreClient.Convenience.cs index ee48aaca..4148a8c1 100644 --- a/src/Custom/VectorStores/VectorStoreClient.Convenience.cs +++ b/src/Custom/VectorStores/VectorStoreClient.Convenience.cs @@ -170,8 +170,11 @@ public virtual ClientResult RemoveFileFromStore(VectorStore vectorStore, O /// The vector store to associate files with. /// The files to associate with the vector store. /// A instance representing the batch operation. - public virtual Task> CreateBatchFileJobAsync(VectorStore vectorStore, IEnumerable files) - => CreateBatchFileJobAsync(vectorStore?.Id, files?.Select(file => file.Id)); + public virtual Task CreateBatchFileJobAsync( + ReturnWhen returnWhen, + VectorStore vectorStore, + IEnumerable files) + => CreateBatchFileJobAsync(returnWhen, vectorStore?.Id, files?.Select(file => file.Id)); /// /// Begins a batch job to associate multiple jobs with a vector store, beginning the ingestion process. @@ -179,69 +182,9 @@ public virtual Task> CreateBatchFileJobAsy /// The vector store to associate files with. /// The files to associate with the vector store. /// A instance representing the batch operation. - public virtual ClientResult CreateBatchFileJob(VectorStore vectorStore, IEnumerable files) - => CreateBatchFileJob(vectorStore?.Id, files?.Select(file => file.Id)); - - /// - /// Gets an updated instance of an existing , refreshing its status. - /// - /// The job to refresh. - /// The refreshed instance of . - public virtual Task> GetBatchFileJobAsync(VectorStoreBatchFileJob batchJob) - => GetBatchFileJobAsync(batchJob?.VectorStoreId, batchJob?.BatchId); - - /// - /// Gets an updated instance of an existing , refreshing its status. - /// - /// The job to refresh. - /// The refreshed instance of . - public virtual ClientResult GetBatchFileJob(VectorStoreBatchFileJob batchJob) - => GetBatchFileJob(batchJob?.VectorStoreId, batchJob?.BatchId); - - /// - /// Cancels an in-progress . - /// - /// The that should be canceled. - /// An updated instance. - public virtual Task> CancelBatchFileJobAsync(VectorStoreBatchFileJob batchJob) - => CancelBatchFileJobAsync(batchJob?.VectorStoreId, batchJob?.BatchId); - - /// - /// Cancels an in-progress . - /// - /// The that should be canceled. - /// An updated instance. - public virtual ClientResult CancelBatchFileJob(VectorStoreBatchFileJob batchJob) - => CancelBatchFileJob(batchJob?.VectorStoreId, batchJob?.BatchId); - - /// - /// Gets a page collection holding file associations associated with a vector store batch file job, representing the files - /// that were scheduled for ingestion into the vector store. - /// - /// The vector store batch file job to retrieve file associations from. - /// Options describing the collection to return. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual AsyncPageCollection GetFileAssociationsAsync( - VectorStoreBatchFileJob batchJob, - VectorStoreFileAssociationCollectionOptions options = default) - => GetFileAssociationsAsync(batchJob?.VectorStoreId, batchJob?.BatchId, options); - - /// - /// Gets a page collection holding file associations associated with a vector store batch file job, representing the files - /// that were scheduled for ingestion into the vector store. - /// - /// The vector store batch file job to retrieve file associations from. - /// Options describing the collection to return. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual PageCollection GetFileAssociations( - VectorStoreBatchFileJob batchJob, - VectorStoreFileAssociationCollectionOptions options = default) - => GetFileAssociations(batchJob?.VectorStoreId, batchJob?.BatchId, options); - + public virtual VectorStoreFileBatchOperation CreateBatchFileJob( + ReturnWhen returnWhen, + VectorStore vectorStore, + IEnumerable files) + => CreateBatchFileJob(returnWhen, vectorStore?.Id, files?.Select(file => file.Id)); } diff --git a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs index ca3fa76b..4adcd361 100644 --- a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs +++ b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs @@ -3,6 +3,7 @@ using System.ClientModel.Primitives; using System.Collections.Generic; using System.ComponentModel; +using System.Text.Json; using System.Threading.Tasks; namespace OpenAI.VectorStores; @@ -433,13 +434,26 @@ public virtual ClientResult RemoveFileFromStore(string vectorStoreId, string fil /// Service returned a non-success status code. /// The response returned from the service. [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task CreateBatchFileJobAsync(string vectorStoreId, BinaryContent content, RequestOptions options = null) + public virtual async Task CreateBatchFileJobAsync(ReturnWhen returnWhen, string vectorStoreId, BinaryContent content, RequestOptions options = null) { Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); Argument.AssertNotNull(content, nameof(content)); using PipelineMessage message = CreateCreateVectorStoreFileBatchRequest(vectorStoreId, content, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + PipelineResponse response = await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string batchId = doc.RootElement.GetProperty("id"u8).GetString(); + string status = doc.RootElement.GetProperty("status"u8).GetString(); + + VectorStoreFileBatchOperation operation = new VectorStoreFileBatchOperation(_pipeline, _endpoint, vectorStoreId, batchId, status, response); + if (returnWhen == ReturnWhen.Started) + { + return operation; + } + + await operation.WaitForCompletionAsync(options?.CancellationToken ?? default).ConfigureAwait(false); + return operation; } /// @@ -453,170 +467,27 @@ public virtual async Task CreateBatchFileJobAsync(string vectorSto /// Service returned a non-success status code. /// The response returned from the service. [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult CreateBatchFileJob(string vectorStoreId, BinaryContent content, RequestOptions options = null) + public virtual VectorStoreFileBatchOperation CreateBatchFileJob( + ReturnWhen returnWhen, + string vectorStoreId, BinaryContent content, RequestOptions options = null) { Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); Argument.AssertNotNull(content, nameof(content)); using PipelineMessage message = CreateCreateVectorStoreFileBatchRequest(vectorStoreId, content, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - /// - /// [Protocol Method] Retrieves a vector store file batch. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch being retrieved. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task GetBatchFileJobAsync(string vectorStoreId, string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(vectorStoreId, batchId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Retrieves a vector store file batch. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch being retrieved. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult GetBatchFileJob(string vectorStoreId, string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(vectorStoreId, batchId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - /// - /// [Protocol Method] Cancel a vector store file batch. This attempts to cancel the processing of files in this batch as soon as possible. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task CancelBatchFileJobAsync(string vectorStoreId, string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateCancelVectorStoreFileBatchRequest(vectorStoreId, batchId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Cancel a vector store file batch. This attempts to cancel the processing of files in this batch as soon as possible. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult CancelBatchFileJob(string vectorStoreId, string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateCancelVectorStoreFileBatchRequest(vectorStoreId, batchId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - /// - /// [Protocol Method] Returns a paginated collection of vector store files in a batch. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch that the files belong to. - /// - /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the - /// default is 20. - /// - /// - /// Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and`desc` - /// for descending order. Allowed values: "asc" | "desc" - /// - /// - /// A cursor for use in pagination. `after` is an object ID that defines your place in the list. - /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - /// subsequent call can include after=obj_foo in order to fetch the next page of the list. - /// - /// - /// A cursor for use in pagination. `before` is an object ID that defines your place in the list. - /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - /// subsequent call can include before=obj_foo in order to fetch the previous page of the list. - /// - /// Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// A collection of service responses, each holding a page of values. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual IAsyncEnumerable GetFileAssociationsAsync(string vectorStoreId, string batchId, int? limit, string order, string after, string before, string filter, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + PipelineResponse response = _pipeline.ProcessMessage(message, options); - VectorStoreFileBatchesPageEnumerator enumerator = new VectorStoreFileBatchesPageEnumerator(_pipeline, _endpoint, vectorStoreId, batchId, limit, order, after, before, filter, options); - return PageCollectionHelpers.CreateAsync(enumerator); - } + using JsonDocument doc = JsonDocument.Parse(response.Content); + string batchId = doc.RootElement.GetProperty("id"u8).GetString(); + string status = doc.RootElement.GetProperty("status"u8).GetString(); - /// - /// [Protocol Method] Returns a paginated collection of vector store files in a batch. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch that the files belong to. - /// - /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the - /// default is 20. - /// - /// - /// Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and`desc` - /// for descending order. Allowed values: "asc" | "desc" - /// - /// - /// A cursor for use in pagination. `after` is an object ID that defines your place in the list. - /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - /// subsequent call can include after=obj_foo in order to fetch the next page of the list. - /// - /// - /// A cursor for use in pagination. `before` is an object ID that defines your place in the list. - /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - /// subsequent call can include before=obj_foo in order to fetch the previous page of the list. - /// - /// Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// A collection of service responses, each holding a page of values. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual IEnumerable GetFileAssociations(string vectorStoreId, string batchId, int? limit, string order, string after, string before, string filter, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + VectorStoreFileBatchOperation operation = new VectorStoreFileBatchOperation(_pipeline, _endpoint, vectorStoreId, batchId, status, response); + if (returnWhen == ReturnWhen.Started) + { + return operation; + } - VectorStoreFileBatchesPageEnumerator enumerator = new VectorStoreFileBatchesPageEnumerator(_pipeline, _endpoint, vectorStoreId, batchId, limit, order, after, before, filter, options); - return PageCollectionHelpers.Create(enumerator); + operation.WaitForCompletion(options?.CancellationToken ?? default); + return operation; } } diff --git a/src/Custom/VectorStores/VectorStoreClient.cs b/src/Custom/VectorStores/VectorStoreClient.cs index 161f4f6a..c87d3cbb 100644 --- a/src/Custom/VectorStores/VectorStoreClient.cs +++ b/src/Custom/VectorStores/VectorStoreClient.cs @@ -15,10 +15,6 @@ namespace OpenAI.VectorStores; [CodeGenClient("VectorStores")] [CodeGenSuppress("CreateVectorStoreAsync", typeof(VectorStoreCreationOptions))] [CodeGenSuppress("CreateVectorStore", typeof(VectorStoreCreationOptions))] -[CodeGenSuppress("GetVectorStoreAsync", typeof(string))] -[CodeGenSuppress("GetVectorStore", typeof(string))] -[CodeGenSuppress("ModifyVectorStoreAsync", typeof(string), typeof(VectorStoreModificationOptions))] -[CodeGenSuppress("ModifyVectorStore", typeof(string), typeof(VectorStoreModificationOptions))] [CodeGenSuppress("DeleteVectorStoreAsync", typeof(string))] [CodeGenSuppress("DeleteVectorStore", typeof(string))] [CodeGenSuppress("GetVectorStoresAsync", typeof(int?), typeof(ListOrder?), typeof(string), typeof(string))] @@ -544,295 +540,70 @@ public virtual ClientResult RemoveFileFromStore(string vectorStoreId, stri /// The IDs of the files to associate with the vector store. /// A token that can be used to cancel this method call. /// A instance representing the batch operation. - public virtual async Task> CreateBatchFileJobAsync(string vectorStoreId, IEnumerable fileIds, CancellationToken cancellationToken = default) + public virtual async Task CreateBatchFileJobAsync( + ReturnWhen returnWhen, + string vectorStoreId, + IEnumerable fileIds, + CancellationToken cancellationToken = default) { Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); Argument.AssertNotNullOrEmpty(fileIds, nameof(fileIds)); BinaryContent content = new InternalCreateVectorStoreFileBatchRequest(fileIds).ToBinaryContent(); - ClientResult result = await CreateBatchFileJobAsync(vectorStoreId, content, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - PipelineResponse response = result?.GetRawResponse(); - VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); - return ClientResult.FromValue(value, response); - } - - /// - /// Begins a batch job to associate multiple jobs with a vector store, beginning the ingestion process. - /// - /// The ID of the vector store to associate files with. - /// The IDs of the files to associate with the vector store. - /// A token that can be used to cancel this method call. - /// A instance representing the batch operation. - public virtual ClientResult CreateBatchFileJob(string vectorStoreId, IEnumerable fileIds, CancellationToken cancellationToken = default) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(fileIds, nameof(fileIds)); + RequestOptions options = cancellationToken.ToRequestOptions(); - BinaryContent content = new InternalCreateVectorStoreFileBatchRequest(fileIds).ToBinaryContent(); - ClientResult result = CreateBatchFileJob(vectorStoreId, content, cancellationToken.ToRequestOptions()); - PipelineResponse response = result?.GetRawResponse(); + using PipelineMessage message = CreateCreateVectorStoreFileBatchRequest(vectorStoreId, content, options); + PipelineResponse response = await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false); VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); - return ClientResult.FromValue(value, response); - } - /// - /// Gets an existing vector store batch file ingestion job from a known vector store ID and job ID. - /// - /// The ID of the vector store into which the batch of files was started. - /// The ID of the batch operation adding files to the vector store. - /// A token that can be used to cancel this method call. - /// A instance representing the ingestion operation. - public virtual async Task> GetBatchFileJobAsync(string vectorStoreId, string batchJobId, CancellationToken cancellationToken = default) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchJobId, nameof(batchJobId)); - - ClientResult result = await GetBatchFileJobAsync(vectorStoreId, batchJobId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - PipelineResponse response = result?.GetRawResponse(); - VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); - return ClientResult.FromValue(value, response); - } - - /// - /// Gets an existing vector store batch file ingestion job from a known vector store ID and job ID. - /// - /// The ID of the vector store into which the batch of files was started. - /// The ID of the batch operation adding files to the vector store. - /// A token that can be used to cancel this method call. - /// A instance representing the ingestion operation. - public virtual ClientResult GetBatchFileJob(string vectorStoreId, string batchJobId, CancellationToken cancellationToken = default) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchJobId, nameof(batchJobId)); + VectorStoreFileBatchOperation operation = new VectorStoreFileBatchOperation( + _pipeline, + _endpoint, + ClientResult.FromValue(value, response)); - ClientResult result = GetBatchFileJob(vectorStoreId, batchJobId, cancellationToken.ToRequestOptions()); - PipelineResponse response = result?.GetRawResponse(); - VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); - return ClientResult.FromValue(value, response); - } - - /// - /// Cancels an in-progress . - /// - /// - /// The ID of the that is the ingestion target of the batch job being cancelled. - /// - /// - /// The ID of the that should be canceled. - /// - /// A token that can be used to cancel this method call. - /// An updated instance. - public virtual async Task> CancelBatchFileJobAsync(string vectorStoreId, string batchJobId, CancellationToken cancellationToken = default) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchJobId, nameof(batchJobId)); - - ClientResult result = await CancelBatchFileJobAsync(vectorStoreId, batchJobId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - PipelineResponse response = result?.GetRawResponse(); - VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); - return ClientResult.FromValue(value, response); - } - - /// - /// Cancels an in-progress . - /// - /// - /// The ID of the that is the ingestion target of the batch job being cancelled. - /// - /// - /// The ID of the that should be canceled. - /// - /// A token that can be used to cancel this method call. - /// An updated instance. - public virtual ClientResult CancelBatchFileJob(string vectorStoreId, string batchJobId, CancellationToken cancellationToken = default) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchJobId, nameof(batchJobId)); - - ClientResult result = CancelBatchFileJob(vectorStoreId, batchJobId, cancellationToken.ToRequestOptions()); - PipelineResponse response = result?.GetRawResponse(); - VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); - return ClientResult.FromValue(value, response); - } - - /// - /// Gets a page collection of file associations associated with a vector store batch file job, representing the files - /// that were scheduled for ingestion into the vector store. - /// - /// - /// The ID of the vector store into which the file batch was scheduled for ingestion. - /// - /// - /// The ID of the batch file job that was previously scheduled. - /// - /// Options describing the collection to return. - /// A token that can be used to cancel this method call. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual AsyncPageCollection GetFileAssociationsAsync( - string vectorStoreId, - string batchJobId, - VectorStoreFileAssociationCollectionOptions options = default, - CancellationToken cancellationToken = default) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchJobId, nameof(batchJobId)); - - VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, - vectorStoreId, - batchJobId, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - options?.Filter?.ToString(), - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); - } - - /// - /// Rehydrates a page collection of file associations from a page token. - /// - /// - /// The ID of the vector store into which the file batch was scheduled for ingestion. - /// - /// - /// The ID of the batch file job that was previously scheduled. - /// - /// Page token corresponding to the first page of the collection to rehydrate. - /// A token that can be used to cancel this method call. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual AsyncPageCollection GetFileAssociationsAsync( - string vectorStoreId, - string batchJobId, - ContinuationToken firstPageToken, - CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); - - VectorStoreFileBatchesPageToken pageToken = VectorStoreFileBatchesPageToken.FromToken(firstPageToken); - - if (vectorStoreId != pageToken.VectorStoreId) - { - throw new ArgumentException( - "Invalid page token. 'vectorStoreId' value does not match page token value.", - nameof(vectorStoreId)); - } - - if (batchJobId != pageToken.BatchId) + if (returnWhen == ReturnWhen.Started) { - throw new ArgumentException( - "Invalid page token. 'batchJobId' value does not match page token value.", - nameof(vectorStoreId)); + return operation; } - VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.VectorStoreId, - pageToken.BatchId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - pageToken.Filter, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); + await operation.WaitForCompletionAsync().ConfigureAwait(false); + return operation; } /// - /// Gets a page collection of file associations associated with a vector store batch file job, representing the files - /// that were scheduled for ingestion into the vector store. + /// Begins a batch job to associate multiple jobs with a vector store, beginning the ingestion process. /// - /// - /// The ID of the vector store into which the file batch was scheduled for ingestion. - /// - /// - /// The ID of the batch file job that was previously scheduled. - /// - /// Options describing the collection to return. + /// The ID of the vector store to associate files with. + /// The IDs of the files to associate with the vector store. /// A token that can be used to cancel this method call. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual PageCollection GetFileAssociations( + /// A instance representing the batch operation. + public virtual VectorStoreFileBatchOperation CreateBatchFileJob( + ReturnWhen returnWhen, string vectorStoreId, - string batchJobId, - VectorStoreFileAssociationCollectionOptions options = default, + IEnumerable fileIds, CancellationToken cancellationToken = default) { Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchJobId, nameof(batchJobId)); - - VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, - vectorStoreId, - batchJobId, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - options?.Filter?.ToString(), - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); - } + Argument.AssertNotNullOrEmpty(fileIds, nameof(fileIds)); - /// - /// Rehydrates a page collection of file associations from a page token. - /// that were scheduled for ingestion into the vector store. - /// - /// - /// The ID of the vector store into which the file batch was scheduled for ingestion. - /// - /// - /// The ID of the batch file job that was previously scheduled. - /// - /// Page token corresponding to the first page of the collection to rehydrate. - /// A token that can be used to cancel this method call. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual PageCollection GetFileAssociations( - string vectorStoreId, - string batchJobId, - ContinuationToken firstPageToken, - CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); + BinaryContent content = new InternalCreateVectorStoreFileBatchRequest(fileIds).ToBinaryContent(); + RequestOptions options = cancellationToken.ToRequestOptions(); - VectorStoreFileBatchesPageToken pageToken = VectorStoreFileBatchesPageToken.FromToken(firstPageToken); + using PipelineMessage message = CreateCreateVectorStoreFileBatchRequest(vectorStoreId, content, options); + PipelineResponse response = _pipeline.ProcessMessage(message, options); + VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); - if (vectorStoreId != pageToken.VectorStoreId) - { - throw new ArgumentException( - "Invalid page token. 'vectorStoreId' value does not match page token value.", - nameof(vectorStoreId)); - } + VectorStoreFileBatchOperation operation = new VectorStoreFileBatchOperation( + _pipeline, + _endpoint, + ClientResult.FromValue(value, response)); - if (batchJobId != pageToken.BatchId) + if (returnWhen == ReturnWhen.Started) { - throw new ArgumentException( - "Invalid page token. 'batchJobId' value does not match page token value.", - nameof(vectorStoreId)); + return operation; } - VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.VectorStoreId, - pageToken.BatchId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - pageToken.Filter, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); + operation.WaitForCompletion(); + return operation; } } diff --git a/src/Generated/BatchClient.cs b/src/Generated/BatchClient.cs index 3ccd2f90..ff92edef 100644 --- a/src/Generated/BatchClient.cs +++ b/src/Generated/BatchClient.cs @@ -81,23 +81,6 @@ internal PipelineMessage CreateRetrieveBatchRequest(string batchId, RequestOptio return message; } - internal PipelineMessage CreateCancelBatchRequest(string batchId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "POST"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/batches/", false); - uri.AppendPath(batchId, true); - uri.AppendPath("/cancel", false); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - private static PipelineMessageClassifier _pipelineMessageClassifier200; private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); } diff --git a/src/Generated/FineTuningClient.cs b/src/Generated/FineTuningClient.cs index 7424e033..1427659e 100644 --- a/src/Generated/FineTuningClient.cs +++ b/src/Generated/FineTuningClient.cs @@ -71,89 +71,6 @@ internal PipelineMessage CreateGetPaginatedFineTuningJobsRequest(string after, i return message; } - internal PipelineMessage CreateRetrieveFineTuningJobRequest(string fineTuningJobId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/fine_tuning/jobs/", false); - uri.AppendPath(fineTuningJobId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateCancelFineTuningJobRequest(string fineTuningJobId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "POST"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/fine_tuning/jobs/", false); - uri.AppendPath(fineTuningJobId, true); - uri.AppendPath("/cancel", false); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateGetFineTuningJobCheckpointsRequest(string fineTuningJobId, string after, int? limit, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/fine_tuning/jobs/", false); - uri.AppendPath(fineTuningJobId, true); - uri.AppendPath("/checkpoints", false); - if (after != null) - { - uri.AppendQuery("after", after, true); - } - if (limit != null) - { - uri.AppendQuery("limit", limit.Value, true); - } - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateGetFineTuningEventsRequest(string fineTuningJobId, string after, int? limit, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/fine_tuning/jobs/", false); - uri.AppendPath(fineTuningJobId, true); - uri.AppendPath("/events", false); - if (after != null) - { - uri.AppendQuery("after", after, true); - } - if (limit != null) - { - uri.AppendQuery("limit", limit.Value, true); - } - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - private static PipelineMessageClassifier _pipelineMessageClassifier200; private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); } diff --git a/src/Generated/VectorStoreClient.cs b/src/Generated/VectorStoreClient.cs index 6f2be46a..61cb80aa 100644 --- a/src/Generated/VectorStoreClient.cs +++ b/src/Generated/VectorStoreClient.cs @@ -240,82 +240,6 @@ internal PipelineMessage CreateCreateVectorStoreFileBatchRequest(string vectorSt return message; } - internal PipelineMessage CreateGetVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/vector_stores/", false); - uri.AppendPath(vectorStoreId, true); - uri.AppendPath("/file_batches/", false); - uri.AppendPath(batchId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateCancelVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "POST"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/vector_stores/", false); - uri.AppendPath(vectorStoreId, true); - uri.AppendPath("/file_batches/", false); - uri.AppendPath(batchId, true); - uri.AppendPath("/cancel", false); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateGetFilesInVectorStoreBatchesRequest(string vectorStoreId, string batchId, int? limit, string order, string after, string before, string filter, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/vector_stores/", false); - uri.AppendPath(vectorStoreId, true); - uri.AppendPath("/file_batches/", false); - uri.AppendPath(batchId, true); - uri.AppendPath("/files", false); - if (limit != null) - { - uri.AppendQuery("limit", limit.Value, true); - } - if (order != null) - { - uri.AppendQuery("order", order, true); - } - if (after != null) - { - uri.AppendQuery("after", after, true); - } - if (before != null) - { - uri.AppendQuery("before", before, true); - } - if (filter != null) - { - uri.AppendQuery("filter", filter, true); - } - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - private static PipelineMessageClassifier _pipelineMessageClassifier200; private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); } diff --git a/src/OpenAI.csproj b/src/OpenAI.csproj index eed204d5..5318c8fc 100644 --- a/src/OpenAI.csproj +++ b/src/OpenAI.csproj @@ -72,6 +72,6 @@ - + diff --git a/src/To.Be.Generated/BatchOperation.Protocol.cs b/src/To.Be.Generated/BatchOperation.Protocol.cs new file mode 100644 index 00000000..bc0398d1 --- /dev/null +++ b/src/To.Be.Generated/BatchOperation.Protocol.cs @@ -0,0 +1,153 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.Batch; + +// Protocol version +public partial class BatchOperation : OperationResult +{ + private readonly ClientPipeline _pipeline; + private readonly Uri _endpoint; + + private readonly string _batchId; + + private PollingInterval _pollingInterval; + + // For use with protocol methods where the response has been obtained prior + // to creation of the LRO instance. + internal BatchOperation( + ClientPipeline pipeline, + Uri endpoint, + string batchId, + string status, + PipelineResponse response) + : base(response) + { + _pipeline = pipeline; + _endpoint = endpoint; + + _batchId = batchId; + + IsCompleted = GetIsCompleted(status); + + _pollingInterval = new(); + + RehydrationToken = new BatchOperationToken(batchId); + } + + public override ContinuationToken? RehydrationToken { get; protected set; } + + public override bool IsCompleted { get; protected set; } + + // These are replaced when LRO is evolved to have conveniences + public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) + { + IAsyncEnumerator enumerator = + new BatchOperationUpdateEnumerator(_pipeline, _endpoint, _batchId, cancellationToken); + + while (await enumerator.MoveNextAsync().ConfigureAwait(false)) + { + ApplyUpdate(enumerator.Current); + + await _pollingInterval.WaitAsync(cancellationToken); + } + } + + public override void WaitForCompletion(CancellationToken cancellationToken = default) + { + IEnumerator enumerator = new BatchOperationUpdateEnumerator( + _pipeline, _endpoint, _batchId, cancellationToken); + + while (enumerator.MoveNext()) + { + ApplyUpdate(enumerator.Current); + + cancellationToken.ThrowIfCancellationRequested(); + + _pollingInterval.Wait(); + } + } + + private void ApplyUpdate(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string? status = doc.RootElement.GetProperty("status"u8).GetString(); + + IsCompleted = GetIsCompleted(status); + SetRawResponse(response); + } + + private static bool GetIsCompleted(string? status) + { + return status == "completed" || + status == "cancelled" || + status == "expired" || + status == "failed"; + } + + // Generated protocol methods + + /// + /// [Protocol Method] Cancels an in-progress batch. + /// + /// The ID of the batch to cancel. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task CancelBatchAsync(string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateCancelBatchRequest(batchId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Cancels an in-progress batch. + /// + /// The ID of the batch to cancel. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult CancelBatch(string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateCancelBatchRequest(batchId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + internal PipelineMessage CreateCancelBatchRequest(string batchId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "POST"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/batches/", false); + uri.AppendPath(batchId, true); + uri.AppendPath("/cancel", false); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); +} \ No newline at end of file diff --git a/src/To.Be.Generated/BatchOperationToken.cs b/src/To.Be.Generated/BatchOperationToken.cs new file mode 100644 index 00000000..41b3b9a1 --- /dev/null +++ b/src/To.Be.Generated/BatchOperationToken.cs @@ -0,0 +1,90 @@ +using System; +using System.ClientModel; +using System.Diagnostics; +using System.IO; +using System.Text.Json; + +#nullable enable + +namespace OpenAI.Batch; + +internal class BatchOperationToken : ContinuationToken +{ + public BatchOperationToken(string batchId) + { + BatchId = batchId; + } + + public string BatchId { get; } + + public override BinaryData ToBytes() + { + using MemoryStream stream = new(); + using Utf8JsonWriter writer = new(stream); + writer.WriteStartObject(); + + writer.WriteString("batchId", BatchId); + + writer.WriteEndObject(); + + writer.Flush(); + stream.Position = 0; + + return BinaryData.FromStream(stream); + } + + public static BatchOperationToken FromToken(ContinuationToken continuationToken) + { + if (continuationToken is BatchOperationToken token) + { + return token; + } + + BinaryData data = continuationToken.ToBytes(); + + if (data.ToMemory().Length == 0) + { + throw new ArgumentException("Failed to create BatchOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + Utf8JsonReader reader = new(data); + + string batchId = null!; + + reader.Read(); + + Debug.Assert(reader.TokenType == JsonTokenType.StartObject); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); + + string propertyName = reader.GetString()!; + + switch (propertyName) + { + case "batchId": + reader.Read(); + Debug.Assert(reader.TokenType == JsonTokenType.String); + batchId = reader.GetString()!; + break; + + default: + throw new JsonException($"Unrecognized property '{propertyName}'."); + } + } + + if (batchId is null) + { + throw new ArgumentException("Failed to create BatchOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + return new(batchId); + } +} + diff --git a/src/To.Be.Generated/BatchOperationUpdateEnumerator.Protocol.cs b/src/To.Be.Generated/BatchOperationUpdateEnumerator.Protocol.cs new file mode 100644 index 00000000..ae568011 --- /dev/null +++ b/src/To.Be.Generated/BatchOperationUpdateEnumerator.Protocol.cs @@ -0,0 +1,165 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.Batch; + +internal partial class BatchOperationUpdateEnumerator : + IAsyncEnumerator, + IEnumerator +{ + private readonly ClientPipeline _pipeline; + private readonly Uri _endpoint; + private readonly CancellationToken _cancellationToken; + + private readonly string _batchId; + + // TODO: does this one need to be nullable? + private ClientResult? _current; + private bool _hasNext = true; + + public BatchOperationUpdateEnumerator( + ClientPipeline pipeline, + Uri endpoint, + string batchId, + CancellationToken cancellationToken) + { + _pipeline = pipeline; + _endpoint = endpoint; + + _batchId = batchId; + + _cancellationToken = cancellationToken; + } + + public ClientResult Current => _current!; + + #region IEnumerator methods + + object IEnumerator.Current => _current!; + + bool IEnumerator.MoveNext() + { + if (!_hasNext) + { + _current = null; + return false; + } + + ClientResult result = GetBatch(_batchId, _cancellationToken.ToRequestOptions()); + + _current = result; + _hasNext = HasNext(result); + + return true; + } + + void IEnumerator.Reset() => _current = null; + + void IDisposable.Dispose() { } + + #endregion + + #region IAsyncEnumerator methods + + ClientResult IAsyncEnumerator.Current => _current!; + + public async ValueTask MoveNextAsync() + { + if (!_hasNext) + { + _current = null; + return false; + } + + ClientResult result = await GetBatchAsync(_batchId, _cancellationToken.ToRequestOptions()).ConfigureAwait(false); + + _current = result; + _hasNext = HasNext(result); + + return true; + } + + // TODO: handle Dispose and DisposeAsync using proper patterns? + ValueTask IAsyncDisposable.DisposeAsync() => default; + + #endregion + + private bool HasNext(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + + // TODO: don't parse JsonDocument twice if possible + using JsonDocument doc = JsonDocument.Parse(response.Content); + string? status = doc.RootElement.GetProperty("status"u8).GetString(); + + bool isComplete = status == "completed" || + status == "cancelled" || + status == "expired" || + status == "failed"; + + return !isComplete; + } + + // Generated methods + + /// + /// [Protocol Method] Retrieves a batch. + /// + /// The ID of the batch to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetBatchAsync(string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateRetrieveBatchRequest(batchId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Retrieves a batch. + /// + /// The ID of the batch to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult GetBatch(string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateRetrieveBatchRequest(batchId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + internal PipelineMessage CreateRetrieveBatchRequest(string batchId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/batches/", false); + uri.AppendPath(batchId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); +} diff --git a/src/To.Be.Generated/FineTuningOperation.Protocol.cs b/src/To.Be.Generated/FineTuningOperation.Protocol.cs new file mode 100644 index 00000000..c4a6dd84 --- /dev/null +++ b/src/To.Be.Generated/FineTuningOperation.Protocol.cs @@ -0,0 +1,344 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.FineTuning; + +public partial class FineTuningOperation : OperationResult +{ + private readonly ClientPipeline _pipeline; + private readonly Uri _endpoint; + + private readonly string _jobId; + + private PollingInterval _pollingInterval; + + internal FineTuningOperation( + ClientPipeline pipeline, + Uri endpoint, + string jobId, + string status, + PipelineResponse response) : base(response) + { + _pipeline = pipeline; + _endpoint = endpoint; + + _jobId = jobId; + IsCompleted = GetIsCompleted(status); + + _pollingInterval = new(); + + RehydrationToken = new FineTuningOperationToken(jobId); + } + + public override ContinuationToken? RehydrationToken { get; protected set; } + + public override bool IsCompleted { get; protected set; } + + public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) + { + IAsyncEnumerator enumerator = new FineTuningOperationUpdateEnumerator( + _pipeline, _endpoint, _jobId, cancellationToken); + + while (await enumerator.MoveNextAsync().ConfigureAwait(false)) + { + ApplyUpdate(enumerator.Current); + + await _pollingInterval.WaitAsync(cancellationToken); + } + } + + public override void WaitForCompletion(CancellationToken cancellationToken = default) + { + IEnumerator enumerator = new FineTuningOperationUpdateEnumerator( + _pipeline, _endpoint, _jobId, cancellationToken); + + while (enumerator.MoveNext()) + { + ApplyUpdate(enumerator.Current); + + cancellationToken.ThrowIfCancellationRequested(); + + _pollingInterval.Wait(); + } + } + + private void ApplyUpdate(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string? status = doc.RootElement.GetProperty("status"u8).GetString(); + + IsCompleted = GetIsCompleted(status); + SetRawResponse(response); + } + + private static bool GetIsCompleted(string? status) + { + return status == "succeeded" || + status == "failed" || + status == "cancelled"; + } + + // Generated protocol methods + + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Get info about a fine-tuning job. + /// + /// [Learn more about fine-tuning](/docs/guides/fine-tuning) + /// + /// The ID of the fine-tuning job. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetJobAsync(string jobId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); + + using PipelineMessage message = CreateRetrieveFineTuningJobRequest(jobId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Get info about a fine-tuning job. + /// + /// [Learn more about fine-tuning](/docs/guides/fine-tuning) + /// + /// The ID of the fine-tuning job. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult GetJob(string jobId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); + + using PipelineMessage message = CreateRetrieveFineTuningJobRequest(jobId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Immediately cancel a fine-tune job. + /// + /// The ID of the fine-tuning job to cancel. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task CancelJobAsync(string jobId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); + + using PipelineMessage message = CreateCancelFineTuningJobRequest(jobId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Immediately cancel a fine-tune job. + /// + /// The ID of the fine-tuning job to cancel. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult CancelJob(string jobId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); + + using PipelineMessage message = CreateCancelFineTuningJobRequest(jobId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Get status updates for a fine-tuning job. + /// + /// The ID of the fine-tuning job to get events for. + /// Identifier for the last event from the previous pagination request. + /// Number of events to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetJobEventsAsync(string jobId, string after, int? limit, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); + + using PipelineMessage message = CreateGetFineTuningEventsRequest(jobId, after, limit, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Get status updates for a fine-tuning job. + /// + /// The ID of the fine-tuning job to get events for. + /// Identifier for the last event from the previous pagination request. + /// Number of events to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult GetJobEvents(string jobId, string after, int? limit, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); + + using PipelineMessage message = CreateGetFineTuningEventsRequest(jobId, after, limit, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] List the checkpoints for a fine-tuning job. + /// + /// The ID of the fine-tuning job to get checkpoints for. + /// Identifier for the last checkpoint ID from the previous pagination request. + /// Number of checkpoints to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetJobCheckpointsAsync(string fineTuningJobId, string after, int? limit, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(fineTuningJobId, nameof(fineTuningJobId)); + + using PipelineMessage message = CreateGetFineTuningJobCheckpointsRequest(fineTuningJobId, after, limit, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] List the checkpoints for a fine-tuning job. + /// + /// The ID of the fine-tuning job to get checkpoints for. + /// Identifier for the last checkpoint ID from the previous pagination request. + /// Number of checkpoints to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult GetJobCheckpoints(string fineTuningJobId, string after, int? limit, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(fineTuningJobId, nameof(fineTuningJobId)); + + using PipelineMessage message = CreateGetFineTuningJobCheckpointsRequest(fineTuningJobId, after, limit, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + internal PipelineMessage CreateRetrieveFineTuningJobRequest(string fineTuningJobId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateCancelFineTuningJobRequest(string fineTuningJobId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "POST"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + uri.AppendPath("/cancel", false); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateGetFineTuningJobCheckpointsRequest(string fineTuningJobId, string after, int? limit, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + uri.AppendPath("/checkpoints", false); + if (after != null) + { + uri.AppendQuery("after", after, true); + } + if (limit != null) + { + uri.AppendQuery("limit", limit.Value, true); + } + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateGetFineTuningEventsRequest(string fineTuningJobId, string after, int? limit, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + uri.AppendPath("/events", false); + if (after != null) + { + uri.AppendQuery("after", after, true); + } + if (limit != null) + { + uri.AppendQuery("limit", limit.Value, true); + } + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); +} diff --git a/src/To.Be.Generated/FineTuningOperationToken.cs b/src/To.Be.Generated/FineTuningOperationToken.cs new file mode 100644 index 00000000..a2f131d3 --- /dev/null +++ b/src/To.Be.Generated/FineTuningOperationToken.cs @@ -0,0 +1,91 @@ +using System; +using System.ClientModel; +using System.Diagnostics; +using System.IO; +using System.Text.Json; + +#nullable enable + +namespace OpenAI.FineTuning; + +internal class FineTuningOperationToken : ContinuationToken +{ + public FineTuningOperationToken(string jobId) + { + JobId = jobId; + } + + public string JobId { get; } + + public override BinaryData ToBytes() + { + using MemoryStream stream = new(); + using Utf8JsonWriter writer = new(stream); + + writer.WriteStartObject(); + + writer.WriteString("jobId", JobId); + + writer.WriteEndObject(); + + writer.Flush(); + stream.Position = 0; + + return BinaryData.FromStream(stream); + } + + public static FineTuningOperationToken FromToken(ContinuationToken continuationToken) + { + if (continuationToken is FineTuningOperationToken token) + { + return token; + } + + BinaryData data = continuationToken.ToBytes(); + + if (data.ToMemory().Length == 0) + { + throw new ArgumentException("Failed to create FineTuningOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + Utf8JsonReader reader = new(data); + + string jobId = null!; + + reader.Read(); + + Debug.Assert(reader.TokenType == JsonTokenType.StartObject); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); + + string propertyName = reader.GetString()!; + + switch (propertyName) + { + case "jobId": + reader.Read(); + Debug.Assert(reader.TokenType == JsonTokenType.String); + jobId = reader.GetString()!; + break; + + default: + throw new JsonException($"Unrecognized property '{propertyName}'."); + } + } + + if (jobId is null) + { + throw new ArgumentException("Failed to create RunOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + return new(jobId); + } +} + diff --git a/src/To.Be.Generated/FineTuningOperationUpdateEnumerator.Protocol.cs b/src/To.Be.Generated/FineTuningOperationUpdateEnumerator.Protocol.cs new file mode 100644 index 00000000..29d75f8e --- /dev/null +++ b/src/To.Be.Generated/FineTuningOperationUpdateEnumerator.Protocol.cs @@ -0,0 +1,170 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.FineTuning; + +internal partial class FineTuningOperationUpdateEnumerator : + IAsyncEnumerator, + IEnumerator +{ + private readonly ClientPipeline _pipeline; + private readonly Uri _endpoint; + private readonly CancellationToken _cancellationToken; + + private readonly string _jobId; + + private ClientResult? _current; + private bool _hasNext = true; + + public FineTuningOperationUpdateEnumerator( + ClientPipeline pipeline, + Uri endpoint, + string jobId, + CancellationToken cancellationToken) + { + _pipeline = pipeline; + _endpoint = endpoint; + + _jobId = jobId; + + _cancellationToken = cancellationToken; + } + + public ClientResult Current => _current!; + + #region IEnumerator methods + + object IEnumerator.Current => _current!; + + bool IEnumerator.MoveNext() + { + if (!_hasNext) + { + _current = null; + return false; + } + + ClientResult result = GetJob(_jobId, _cancellationToken.ToRequestOptions()); + + _current = result; + _hasNext = HasNext(result); + + return true; + } + + void IEnumerator.Reset() => _current = null; + + void IDisposable.Dispose() { } + + #endregion + + #region IAsyncEnumerator methods + + ClientResult IAsyncEnumerator.Current => _current!; + + public async ValueTask MoveNextAsync() + { + if (!_hasNext) + { + _current = null; + return false; + } + + ClientResult result = await GetJobAsync(_jobId, _cancellationToken.ToRequestOptions()).ConfigureAwait(false); + + _current = result; + _hasNext = HasNext(result); + + return true; + } + + // TODO: handle Dispose and DisposeAsync using proper patterns? + ValueTask IAsyncDisposable.DisposeAsync() => default; + + #endregion + + private bool HasNext(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + + // TODO: don't parse JsonDocument twice if possible + using JsonDocument doc = JsonDocument.Parse(response.Content); + string? status = doc.RootElement.GetProperty("status"u8).GetString(); + + bool isComplete = status == "succeeded" || + status == "failed" || + status == "cancelled"; + + return !isComplete; + } + + // Generated methods + + /// + /// [Protocol Method] Get info about a fine-tuning job. + /// + /// [Learn more about fine-tuning](/docs/guides/fine-tuning) + /// + /// The ID of the fine-tuning job. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetJobAsync(string jobId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); + + using PipelineMessage message = CreateRetrieveFineTuningJobRequest(jobId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Get info about a fine-tuning job. + /// + /// [Learn more about fine-tuning](/docs/guides/fine-tuning) + /// + /// The ID of the fine-tuning job. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult GetJob(string jobId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); + + using PipelineMessage message = CreateRetrieveFineTuningJobRequest(jobId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + internal PipelineMessage CreateRetrieveFineTuningJobRequest(string fineTuningJobId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); +} diff --git a/src/To.Be.Generated/Internal/PollingInterval.cs b/src/To.Be.Generated/Internal/PollingInterval.cs new file mode 100644 index 00000000..d159aabd --- /dev/null +++ b/src/To.Be.Generated/Internal/PollingInterval.cs @@ -0,0 +1,29 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI; + +internal class PollingInterval +{ + private const int DefaultWaitMilliseconds = 1000; + + private readonly TimeSpan _interval; + + public PollingInterval(TimeSpan? interval = default) + { + _interval = interval ?? new TimeSpan(DefaultWaitMilliseconds); + } + + public async Task WaitAsync(CancellationToken cancellationToken) + { + await Task.Delay(_interval, cancellationToken); + } + + public void Wait() + { + Thread.Sleep(_interval); + } +} diff --git a/src/To.Be.Generated/RunOperation.Protocol.cs b/src/To.Be.Generated/RunOperation.Protocol.cs new file mode 100644 index 00000000..5d9b6c0e --- /dev/null +++ b/src/To.Be.Generated/RunOperation.Protocol.cs @@ -0,0 +1,639 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text.Json; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.Assistants; + +// Protocol version +public partial class RunOperation : ClientResult +{ + private readonly ClientPipeline _pipeline; + private readonly Uri _endpoint; + + private string? _threadId; + private string? _runId; + private string? _status; + + private bool _isCompleted; + + private PollingInterval? _pollingInterval; + + // For use with protocol methods where the response has been obtained prior + // to creation of the LRO instance. + internal RunOperation( + ClientPipeline pipeline, + Uri endpoint, + PipelineResponse response) + : base(response) + { + _pipeline = pipeline; + _endpoint = endpoint; + + // Protocol method was called with stream=true option. + bool isStreaming = + response.Headers.TryGetValue("Content-Type", out string? contentType) && + contentType == "text/event-stream; charset=utf-8"; + + if (!isStreaming) + { + _pollingInterval = new(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + + _status = doc.RootElement.GetProperty("status"u8).GetString(); + _threadId = doc.RootElement.GetProperty("thread_id"u8).GetString(); + _runId = doc.RootElement.GetProperty("id"u8).GetString(); + + if (_status is null || _threadId is null || _runId is null) + { + throw new ArgumentException("Invalid 'response' body.", nameof(response)); + } + + IsCompleted = GetIsCompleted(_status!); + } + } + + #region OperationResult methods + + public virtual bool IsCompleted + { + get + { + // We need this check in the protocol/streaming case. + if (IsStreaming) + { + throw new NotSupportedException("Cannot obtain operation status from streaming operation."); + } + + return _isCompleted; + } + + protected set => _isCompleted = value; + } + + public virtual ContinuationToken? RehydrationToken { get; protected set; } + + internal bool IsStreaming => _pollingInterval == null; + + // Note: these work for protocol-only. + // Once convenience overloads available, these get replaced by those implementations. + + //public override Task WaitAsync(CancellationToken cancellationToken = default) + //{ + // if (_isStreaming) + // { + // // We would have to read from the stream to get the run ID to poll for. + // throw new NotSupportedException("Cannot poll for status updates from streaming operation."); + // } + + // // See: https://platform.openai.com/docs/assistants/how-it-works/polling-for-updates + + // IAsyncEnumerator enumerator = GetUpdateResultEnumeratorAsync(); + + // await while (await enumerator.MoveNextAsync().ConfigureAwait(false)) + // { + // ApplyUpdate(enumerator.Current); + + // // Don't keep polling if would do so infinitely. + // if (_status == "requires_action") + // { + // return; + // } + + // cancellationToken.ThrowIfCancellationRequested(); + + // await _pollingInterval.WaitAsync().ConfigureAwait(); + // } + //} + + //public override void Wait(CancellationToken cancellationToken = default) + //{ + // if (_isStreaming) + // { + // // We would have to read from the stream to get the run ID to poll for. + // throw new NotSupportedException("Cannot poll for status updates from streaming operation."); + // } + + // // See: https://platform.openai.com/docs/assistants/how-it-works/polling-for-updates + + // IEnumerator enumerator = GetUpdateResultEnumerator(); + + // while (enumerator.MoveNext()) + // { + // ApplyUpdate(enumerator.Current); + + // // Don't keep polling if would do so infinitely. + // if (_status == "requires_action") + // { + // return; + // } + + // cancellationToken.ThrowIfCancellationRequested(); + + // _pollingInterval.Wait(); + // } + //} + + //private void ApplyUpdate(ClientResult result) + //{ + // PipelineResponse response = result.GetRawResponse(); + + // using JsonDocument doc = JsonDocument.Parse(response.Content); + // _status = doc.RootElement.GetProperty("status"u8).GetString(); + + // IsCompleted = GetIsCompleted(_status!); + // SetRawResponse(response); + //} + + private static bool GetIsCompleted(string status) + { + bool hasCompleted = + status == "expired" || + status == "completed" || + status == "failed" || + status == "incomplete" || + status == "cancelled"; + + return hasCompleted; + } + + #endregion + + #region Generated protocol methods - i.e. TypeSpec "linked operations" + + /// + /// [Protocol Method] Retrieves a run. + /// + /// The ID of the [thread](/docs/api-reference/threads) that was run. + /// The ID of the run to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task GetRunAsync(string threadId, string runId, RequestOptions? options) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + + using PipelineMessage message = CreateGetRunRequest(threadId, runId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Retrieves a run. + /// + /// The ID of the [thread](/docs/api-reference/threads) that was run. + /// The ID of the run to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult GetRun(string threadId, string runId, RequestOptions? options) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + + using PipelineMessage message = CreateGetRunRequest(threadId, runId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Modifies a run. + /// + /// The ID of the [thread](/docs/api-reference/threads) that was run. + /// The ID of the run to modify. + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// , or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task ModifyRunAsync(string threadId, string runId, BinaryContent content, RequestOptions? options = null) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateModifyRunRequest(threadId, runId, content, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Modifies a run. + /// + /// The ID of the [thread](/docs/api-reference/threads) that was run. + /// The ID of the run to modify. + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// , or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult ModifyRun(string threadId, string runId, BinaryContent content, RequestOptions? options = null) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateModifyRunRequest(threadId, runId, content, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Cancels a run that is `in_progress`. + /// + /// The ID of the thread to which this run belongs. + /// The ID of the run to cancel. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task CancelRunAsync(string threadId, string runId, RequestOptions? options) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + + using PipelineMessage message = CreateCancelRunRequest(threadId, runId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Cancels a run that is `in_progress`. + /// + /// The ID of the thread to which this run belongs. + /// The ID of the run to cancel. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult CancelRun(string threadId, string runId, RequestOptions? options) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + + using PipelineMessage message = CreateCancelRunRequest(threadId, runId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] When a run has the `status: "requires_action"` and `required_action.type` is + /// `submit_tool_outputs`, this endpoint can be used to submit the outputs from the tool calls once + /// they're all completed. All outputs must be submitted in a single request. + /// + /// The ID of the [thread](/docs/api-reference/threads) to which this run belongs. + /// The ID of the run that requires the tool output submission. + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// , or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task SubmitToolOutputsToRunAsync(string threadId, string runId, BinaryContent content, RequestOptions? options = null) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + Argument.AssertNotNull(content, nameof(content)); + + PipelineMessage? message = null; + try + { + message = CreateSubmitToolOutputsToRunRequest(threadId, runId, content, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + finally + { + if (options?.BufferResponse != false) + { + message?.Dispose(); + } + } + } + + /// + /// [Protocol Method] When a run has the `status: "requires_action"` and `required_action.type` is + /// `submit_tool_outputs`, this endpoint can be used to submit the outputs from the tool calls once + /// they're all completed. All outputs must be submitted in a single request. + /// + /// The ID of the [thread](/docs/api-reference/threads) to which this run belongs. + /// The ID of the run that requires the tool output submission. + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// , or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult SubmitToolOutputsToRun(string threadId, string runId, BinaryContent content, RequestOptions? options = null) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + Argument.AssertNotNull(content, nameof(content)); + + PipelineMessage? message = null; + try + { + message = CreateSubmitToolOutputsToRunRequest(threadId, runId, content, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + finally + { + if (options?.BufferResponse != false) + { + message?.Dispose(); + } + } + } + + /// + /// [Protocol Method] Returns a paginated collection of run steps belonging to a run. + /// + /// The ID of the thread the run and run steps belong to. + /// The ID of the run the run steps belong to. + /// + /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the + /// default is 20. + /// + /// + /// Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and`desc` + /// for descending order. Allowed values: "asc" | "desc" + /// + /// + /// A cursor for use in pagination. `after` is an object ID that defines your place in the list. + /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + /// subsequent call can include after=obj_foo in order to fetch the next page of the list. + /// + /// + /// A cursor for use in pagination. `before` is an object ID that defines your place in the list. + /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + /// subsequent call can include before=obj_foo in order to fetch the previous page of the list. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// A collection of service responses, each holding a page of values. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual IAsyncEnumerable GetRunStepsAsync(string threadId, string runId, int? limit, string order, string after, string before, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + + RunStepsPageEnumerator enumerator = new RunStepsPageEnumerator(_pipeline, _endpoint, threadId, runId, limit, order, after, before, options); + return PageCollectionHelpers.CreateAsync(enumerator); + } + + /// + /// [Protocol Method] Returns a paginated collection of run steps belonging to a run. + /// + /// The ID of the thread the run and run steps belong to. + /// The ID of the run the run steps belong to. + /// + /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the + /// default is 20. + /// + /// + /// Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and`desc` + /// for descending order. Allowed values: "asc" | "desc" + /// + /// + /// A cursor for use in pagination. `after` is an object ID that defines your place in the list. + /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + /// subsequent call can include after=obj_foo in order to fetch the next page of the list. + /// + /// + /// A cursor for use in pagination. `before` is an object ID that defines your place in the list. + /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + /// subsequent call can include before=obj_foo in order to fetch the previous page of the list. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// A collection of service responses, each holding a page of values. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual IEnumerable GetRunSteps(string threadId, string runId, int? limit, string order, string after, string before, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + + RunStepsPageEnumerator enumerator = new RunStepsPageEnumerator(_pipeline, _endpoint, threadId, runId, limit, order, after, before, options); + return PageCollectionHelpers.Create(enumerator); + } + + /// + /// [Protocol Method] Retrieves a run step. + /// + /// The ID of the thread to which the run and run step belongs. + /// The ID of the run to which the run step belongs. + /// The ID of the run step to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// , or is null. + /// , or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task GetRunStepAsync(string threadId, string runId, string stepId, RequestOptions? options) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + Argument.AssertNotNullOrEmpty(stepId, nameof(stepId)); + + using PipelineMessage message = CreateGetRunStepRequest(threadId, runId, stepId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Retrieves a run step. + /// + /// The ID of the thread to which the run and run step belongs. + /// The ID of the run to which the run step belongs. + /// The ID of the run step to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// , or is null. + /// , or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult GetRunStep(string threadId, string runId, string stepId, RequestOptions? options) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + Argument.AssertNotNullOrEmpty(stepId, nameof(stepId)); + + using PipelineMessage message = CreateGetRunStepRequest(threadId, runId, stepId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + internal PipelineMessage CreateCreateRunRequest(string threadId, BinaryContent content, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "POST"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/threads/", false); + uri.AppendPath(threadId, true); + uri.AppendPath("/runs", false); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + request.Headers.Set("Content-Type", "application/json"); + request.Content = content; + message.Apply(options); + return message; + } + + internal PipelineMessage CreateGetRunRequest(string threadId, string runId, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/threads/", false); + uri.AppendPath(threadId, true); + uri.AppendPath("/runs/", false); + uri.AppendPath(runId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateModifyRunRequest(string threadId, string runId, BinaryContent content, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "POST"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/threads/", false); + uri.AppendPath(threadId, true); + uri.AppendPath("/runs/", false); + uri.AppendPath(runId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + request.Headers.Set("Content-Type", "application/json"); + request.Content = content; + message.Apply(options); + return message; + } + + internal PipelineMessage CreateCancelRunRequest(string threadId, string runId, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "POST"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/threads/", false); + uri.AppendPath(threadId, true); + uri.AppendPath("/runs/", false); + uri.AppendPath(runId, true); + uri.AppendPath("/cancel", false); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateSubmitToolOutputsToRunRequest(string threadId, string runId, BinaryContent content, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "POST"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/threads/", false); + uri.AppendPath(threadId, true); + uri.AppendPath("/runs/", false); + uri.AppendPath(runId, true); + uri.AppendPath("/submit_tool_outputs", false); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + request.Headers.Set("Content-Type", "application/json"); + request.Content = content; + message.Apply(options); + return message; + } + + internal PipelineMessage CreateGetRunStepsRequest(string threadId, string runId, int? limit, string order, string after, string before, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/threads/", false); + uri.AppendPath(threadId, true); + uri.AppendPath("/runs/", false); + uri.AppendPath(runId, true); + uri.AppendPath("/steps", false); + if (limit != null) + { + uri.AppendQuery("limit", limit.Value, true); + } + if (order != null) + { + uri.AppendQuery("order", order, true); + } + if (after != null) + { + uri.AppendQuery("after", after, true); + } + if (before != null) + { + uri.AppendQuery("before", before, true); + } + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateGetRunStepRequest(string threadId, string runId, string stepId, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/threads/", false); + uri.AppendPath(threadId, true); + uri.AppendPath("/runs/", false); + uri.AppendPath(runId, true); + uri.AppendPath("/steps/", false); + uri.AppendPath(stepId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); + #endregion +} \ No newline at end of file diff --git a/src/To.Be.Generated/RunOperation.cs b/src/To.Be.Generated/RunOperation.cs new file mode 100644 index 00000000..e2c53430 --- /dev/null +++ b/src/To.Be.Generated/RunOperation.cs @@ -0,0 +1,392 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.Assistants; + +// Convenience version +public partial class RunOperation : ClientResult +{ + // For use with polling convenience methods where the response has been + // obtained prior to creation of the LRO type. + internal RunOperation( + ClientPipeline pipeline, + Uri endpoint, + ThreadRun value, + RunStatus status, + PipelineResponse response) + : base(response) + { + _pipeline = pipeline; + _endpoint = endpoint; + _pollingInterval = new(); + + if (response.Headers.TryGetValue("Content-Type", out string? contentType) && + contentType == "text/event-stream; charset=utf-8") + { + throw new ArgumentException("Cannot create polling operation from streaming response.", nameof(response)); + } + + Value = value; + Status = status; + + ThreadId = value.ThreadId; + RunId = value.Id; + + RehydrationToken = new RunOperationToken(value.ThreadId, value.Id); + } + + // For use with streaming convenience methods - response hasn't been provided yet. + internal RunOperation( + ClientPipeline pipeline, + Uri endpoint) + : base() + { + _pipeline = pipeline; + _endpoint = endpoint; + + // This constructor is provided for streaming convenience method only. + // Because of this, we don't set the polling interval type. + } + + // Note: these all have to be nullable because the derived streaming type + // cannot set them until it reads the first event from the SSE stream. + public string? RunId { get => _runId; protected set => _runId = value; } + public string? ThreadId { get => _threadId; protected set => _threadId = value; } + + public ThreadRun? Value { get; protected set; } + public RunStatus? Status { get; protected set; } + + #region OperationResult methods + + public virtual async Task WaitUntilStoppedAsync(CancellationToken cancellationToken = default) + => await WaitUntilStoppedAsync(default, cancellationToken).ConfigureAwait(false); + + public virtual void WaitUntilStopped(CancellationToken cancellationToken = default) + => WaitUntilStopped(default, cancellationToken); + + public virtual async Task WaitUntilStoppedAsync(TimeSpan? pollingInterval, CancellationToken cancellationToken = default) + { + if (IsStreaming) + { + // We would have to read from the stream to get the run ID to poll for. + throw new NotSupportedException("Cannot poll for status updates from streaming operation."); + } + + await foreach (ThreadRun update in GetUpdatesAsync(pollingInterval, cancellationToken)) + { + // Don't keep polling if would do so infinitely. + if (update.Status == RunStatus.RequiresAction) + { + return; + } + } + } + + public virtual void WaitUntilStopped(TimeSpan? pollingInterval, CancellationToken cancellationToken = default) + { + if (IsStreaming) + { + // We would have to read from the stream to get the run ID to poll for. + throw new NotSupportedException("Cannot poll for status updates from streaming operation."); + } + + foreach (ThreadRun update in GetUpdates(pollingInterval, cancellationToken)) + { + // Don't keep polling if would do so infinitely. + if (update.Status == RunStatus.RequiresAction) + { + return; + } + } + } + + // Expose enumerable APIs similar to the streaming ones. + public virtual async IAsyncEnumerable GetUpdatesAsync( + TimeSpan? pollingInterval = default, + [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + if (pollingInterval is not null) + { + // TODO: don't allocate + _pollingInterval = new PollingInterval(pollingInterval); + } + + IAsyncEnumerator> enumerator = + new RunOperationUpdateEnumerator(_pipeline, _endpoint, _threadId!, _runId!, cancellationToken); + + while (await enumerator.MoveNextAsync().ConfigureAwait(false)) + { + ApplyUpdate(enumerator.Current); + + yield return enumerator.Current; + + // TODO: do we need null check? + await _pollingInterval!.WaitAsync(cancellationToken).ConfigureAwait(false); + } + } + + public virtual IEnumerable GetUpdates( + TimeSpan? pollingInterval = default, + CancellationToken cancellationToken = default) + { + if (pollingInterval is not null) + { + // TODO: don't allocate + _pollingInterval = new PollingInterval(pollingInterval); + } + + IEnumerator> enumerator = new RunOperationUpdateEnumerator( + _pipeline, _endpoint, _threadId!, _runId!, cancellationToken); + + while (enumerator.MoveNext()) + { + ApplyUpdate(enumerator.Current); + + yield return enumerator.Current; + + // TODO: do we need null check? + _pollingInterval!.Wait(); + } + } + + private void ApplyUpdate(ClientResult update) + { + Value = update; + Status = update.Value.Status; + IsCompleted = Status.Value.IsTerminal; + + SetRawResponse(update.GetRawResponse()); + } + + #endregion + + #region Convenience overloads of generated protocol methods + + /// + /// Gets an existing from a known . + /// + /// A token that can be used to cancel this method call. + /// The existing instance. + public virtual async Task> GetRunAsync(CancellationToken cancellationToken = default) + { + ClientResult protocolResult = await GetRunAsync(_threadId!, _runId!, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + return CreateResultFromProtocol(protocolResult, ThreadRun.FromResponse); + } + + /// + /// Gets an existing from a known . + /// + /// A token that can be used to cancel this method call. + /// The existing instance. + public virtual ClientResult GetRun(CancellationToken cancellationToken = default) + { + ClientResult protocolResult = GetRun(_threadId!, _runId!, cancellationToken.ToRequestOptions()); + return CreateResultFromProtocol(protocolResult, ThreadRun.FromResponse); + } + + /// + /// Cancels an in-progress . + /// + /// A token that can be used to cancel this method call. + /// An updated instance, reflecting the new status of the run. + public virtual async Task> CancelRunAsync(CancellationToken cancellationToken = default) + { + ClientResult protocolResult = await CancelRunAsync(_threadId!, _runId!, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + return CreateResultFromProtocol(protocolResult, ThreadRun.FromResponse); + } + + /// + /// Cancels an in-progress . + /// + /// A token that can be used to cancel this method call. + /// An updated instance, reflecting the new status of the run. + public virtual ClientResult CancelRun(CancellationToken cancellationToken = default) + { + ClientResult protocolResult = CancelRun(_threadId!, _runId!, cancellationToken.ToRequestOptions()); + return CreateResultFromProtocol(protocolResult, ThreadRun.FromResponse); + } + + /// + /// Submits a collection of required tool call outputs to a run and resumes the run. + /// + /// + /// The tool outputs, corresponding to instances from the run. + /// + /// A token that can be used to cancel this method call. + /// The , updated after the submission was processed. + public virtual async Task SubmitToolOutputsToRunAsync( + IEnumerable toolOutputs, + CancellationToken cancellationToken = default) + { + BinaryContent content = new InternalSubmitToolOutputsRunRequest(toolOutputs).ToBinaryContent(); + ClientResult protocolResult = await SubmitToolOutputsToRunAsync(_threadId!, _runId!, content, cancellationToken.ToRequestOptions()) + .ConfigureAwait(false); + ClientResult update = CreateResultFromProtocol(protocolResult, ThreadRun.FromResponse); + ApplyUpdate(update); + } + + /// + /// Submits a collection of required tool call outputs to a run and resumes the run. + /// + /// + /// The tool outputs, corresponding to instances from the run. + /// + /// A token that can be used to cancel this method call. + /// The , updated after the submission was processed. + public virtual void SubmitToolOutputsToRun( + IEnumerable toolOutputs, + CancellationToken cancellationToken = default) + { + BinaryContent content = new InternalSubmitToolOutputsRunRequest(toolOutputs).ToBinaryContent(); + ClientResult protocolResult = SubmitToolOutputsToRun(_threadId!, _runId!, content, cancellationToken.ToRequestOptions()); + ClientResult update = CreateResultFromProtocol(protocolResult, ThreadRun.FromResponse); + ApplyUpdate(update); + } + + /// + /// Gets a page collection holding instances associated with a . + /// + /// + /// A token that can be used to cancel this method call. + /// holds pages of values. To obtain a collection of values, call + /// . To obtain the current + /// page of values, call . + /// A collection of pages of . + public virtual AsyncPageCollection GetRunStepsAsync( + RunStepCollectionOptions? options = default, + CancellationToken cancellationToken = default) + { + RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, + _threadId!, + _runId!, + options?.PageSize, + options?.Order?.ToString(), + options?.AfterId, + options?.BeforeId, + cancellationToken.ToRequestOptions()); + + return PageCollectionHelpers.CreateAsync(enumerator); + } + + /// + /// Rehydrates a page collection holding instances from a page token. + /// + /// Page token corresponding to the first page of the collection to rehydrate. + /// A token that can be used to cancel this method call. + /// holds pages of values. To obtain a collection of values, call + /// . To obtain the current + /// page of values, call . + /// A collection of pages of . + public virtual AsyncPageCollection GetRunStepsAsync( + ContinuationToken firstPageToken, + CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); + + RunStepsPageToken pageToken = RunStepsPageToken.FromToken(firstPageToken); + RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, + pageToken.ThreadId, + pageToken.RunId, + pageToken.Limit, + pageToken.Order, + pageToken.After, + pageToken.Before, + cancellationToken.ToRequestOptions()); + + return PageCollectionHelpers.CreateAsync(enumerator); + } + + /// + /// Gets a page collection holding instances associated with a . + /// + /// + /// A token that can be used to cancel this method call. + /// holds pages of values. To obtain a collection of values, call + /// . To obtain the current + /// page of values, call . + /// A collection of pages of . + public virtual PageCollection GetRunSteps( + RunStepCollectionOptions? options = default, + CancellationToken cancellationToken = default) + { + RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, + ThreadId!, + RunId!, + options?.PageSize, + options?.Order?.ToString(), + options?.AfterId, + options?.BeforeId, + cancellationToken.ToRequestOptions()); + + return PageCollectionHelpers.Create(enumerator); + } + + /// + /// Rehydrates a page collection holding instances from a page token. + /// + /// Page token corresponding to the first page of the collection to rehydrate. + /// A token that can be used to cancel this method call. + /// holds pages of values. To obtain a collection of values, call + /// . To obtain the current + /// page of values, call . + /// A collection of pages of . + public virtual PageCollection GetRunSteps( + ContinuationToken firstPageToken, + CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); + + RunStepsPageToken pageToken = RunStepsPageToken.FromToken(firstPageToken); + RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, + pageToken.ThreadId, + pageToken.RunId, + pageToken.Limit, + pageToken.Order, + pageToken.After, + pageToken.Before, + cancellationToken.ToRequestOptions()); + + return PageCollectionHelpers.Create(enumerator); + } + + /// + /// Gets a single run step from a run. + /// + /// The ID of the run step. + /// A token that can be used to cancel this method call. + /// A instance corresponding to the specified step. + public virtual async Task> GetRunStepAsync(string stepId, CancellationToken cancellationToken = default) + { + ClientResult protocolResult = await GetRunStepAsync(_threadId!, _runId!, stepId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + return CreateResultFromProtocol(protocolResult, RunStep.FromResponse); + } + + /// + /// Gets a single run step from a run. + /// + /// The ID of the run step. + /// A token that can be used to cancel this method call. + /// A instance corresponding to the specified step. + public virtual ClientResult GetRunStep(string stepId, CancellationToken cancellationToken = default) + { + ClientResult protocolResult = GetRunStep(_threadId!, _runId!, stepId, cancellationToken.ToRequestOptions()); + return CreateResultFromProtocol(protocolResult, RunStep.FromResponse); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ClientResult CreateResultFromProtocol(ClientResult protocolResult, Func responseDeserializer) + { + PipelineResponse pipelineResponse = protocolResult.GetRawResponse(); + T deserializedResultValue = responseDeserializer.Invoke(pipelineResponse); + return ClientResult.FromValue(deserializedResultValue, pipelineResponse); + } + + #endregion +} \ No newline at end of file diff --git a/src/To.Be.Generated/RunOperationToken.cs b/src/To.Be.Generated/RunOperationToken.cs new file mode 100644 index 00000000..b57dec15 --- /dev/null +++ b/src/To.Be.Generated/RunOperationToken.cs @@ -0,0 +1,102 @@ +using System; +using System.ClientModel; +using System.Diagnostics; +using System.IO; +using System.Text.Json; + +#nullable enable + +namespace OpenAI.Assistants; + +internal class RunOperationToken : ContinuationToken +{ + public RunOperationToken(string threadId, string runId) + { + ThreadId = threadId; + RunId = runId; + } + + public string ThreadId { get; } + + public string RunId { get; } + + public override BinaryData ToBytes() + { + using MemoryStream stream = new(); + using Utf8JsonWriter writer = new(stream); + + writer.WriteStartObject(); + + writer.WriteString("threadId", ThreadId); + writer.WriteString("runId", RunId); + + writer.WriteEndObject(); + + writer.Flush(); + stream.Position = 0; + + return BinaryData.FromStream(stream); + } + + public static RunOperationToken FromToken(ContinuationToken continuationToken) + { + if (continuationToken is RunOperationToken token) + { + return token; + } + + BinaryData data = continuationToken.ToBytes(); + + if (data.ToMemory().Length == 0) + { + throw new ArgumentException("Failed to create RunOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + Utf8JsonReader reader = new(data); + + string threadId = null!; + string runId = null!; + + reader.Read(); + + Debug.Assert(reader.TokenType == JsonTokenType.StartObject); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); + + string propertyName = reader.GetString()!; + + switch (propertyName) + { + case "threadId": + reader.Read(); + Debug.Assert(reader.TokenType == JsonTokenType.String); + threadId = reader.GetString()!; + break; + + case "runId": + reader.Read(); + Debug.Assert(reader.TokenType == JsonTokenType.String); + threadId = reader.GetString()!; + break; + + default: + throw new JsonException($"Unrecognized property '{propertyName}'."); + } + } + + if (threadId is null || runId is null) + { + throw new ArgumentException("Failed to create RunOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + return new(threadId, runId); + } +} + diff --git a/src/To.Be.Generated/RunOperationUpdateEnumerator.Protocol.cs b/src/To.Be.Generated/RunOperationUpdateEnumerator.Protocol.cs new file mode 100644 index 00000000..3185d0b0 --- /dev/null +++ b/src/To.Be.Generated/RunOperationUpdateEnumerator.Protocol.cs @@ -0,0 +1,175 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.Assistants; + +internal partial class RunOperationUpdateEnumerator : + IAsyncEnumerator, + IEnumerator +{ + private readonly ClientPipeline _pipeline; + private readonly Uri _endpoint; + private readonly string _threadId; + private readonly string _runId; + private readonly CancellationToken _cancellationToken; + + private ClientResult? _current; + private bool _hasNext = true; + + public RunOperationUpdateEnumerator( + ClientPipeline pipeline, + Uri endpoint, + string threadId, + string runId, + CancellationToken cancellationToken) + { + _pipeline = pipeline; + _endpoint = endpoint; + + _threadId = threadId; + _runId = runId; + + _cancellationToken = cancellationToken; + } + + public ClientResult Current => _current!; + + #region IEnumerator methods + + object IEnumerator.Current => _current!; + + bool IEnumerator.MoveNext() + { + if (!_hasNext) + { + _current = null; + return false; + } + + ClientResult result = GetRun(_threadId, _runId, _cancellationToken.ToRequestOptions()); + + _current = result; + _hasNext = HasNext(result); + + return true; + } + + void IEnumerator.Reset() => _current = null; + + void IDisposable.Dispose() { } + + #endregion + + #region IAsyncEnumerator methods + + ClientResult IAsyncEnumerator.Current => _current!; + + public async ValueTask MoveNextAsync() + { + if (!_hasNext) + { + _current = null; + return false; + } + + ClientResult result = await GetRunAsync(_threadId, _runId, _cancellationToken.ToRequestOptions()).ConfigureAwait(false); + + _current = result; + _hasNext = HasNext(result); + + return true; + } + + // TODO: handle Dispose and DisposeAsync using proper patterns? + ValueTask IAsyncDisposable.DisposeAsync() => default; + + #endregion + + // Methods used by both implementations + + private bool HasNext(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + + // TODO: don't parse JsonDocument twice if possible + using JsonDocument doc = JsonDocument.Parse(response.Content); + string? status = doc.RootElement.GetProperty("status"u8).GetString(); + + bool isComplete = status == "expired" || + status == "completed" || + status == "failed" || + status == "incomplete" || + status == "cancelled"; + + return !isComplete; + } + + // Generated methods + + /// + /// [Protocol Method] Retrieves a run. + /// + /// The ID of the [thread](/docs/api-reference/threads) that was run. + /// The ID of the run to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetRunAsync(string threadId, string runId, RequestOptions? options) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + + using PipelineMessage message = CreateGetRunRequest(threadId, runId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Retrieves a run. + /// + /// The ID of the [thread](/docs/api-reference/threads) that was run. + /// The ID of the run to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult GetRun(string threadId, string runId, RequestOptions? options) + { + Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + + using PipelineMessage message = CreateGetRunRequest(threadId, runId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + internal PipelineMessage CreateGetRunRequest(string threadId, string runId, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/threads/", false); + uri.AppendPath(threadId, true); + uri.AppendPath("/runs/", false); + uri.AppendPath(runId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); +} diff --git a/src/To.Be.Generated/RunOperationUpdateEnumerator.cs b/src/To.Be.Generated/RunOperationUpdateEnumerator.cs new file mode 100644 index 00000000..8d485771 --- /dev/null +++ b/src/To.Be.Generated/RunOperationUpdateEnumerator.cs @@ -0,0 +1,54 @@ +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; + +#nullable enable + +namespace OpenAI.Assistants; + +internal partial class RunOperationUpdateEnumerator : + IAsyncEnumerator>, + IEnumerator> +{ + #region IEnumerator> methods + + ClientResult IEnumerator>.Current + { + get + { + if (Current is null) + { + return default!; + } + + return GetUpdateFromResult(Current); + } + } + + #endregion + + #region IAsyncEnumerator> methods + + ClientResult IAsyncEnumerator>.Current + { + get + { + if (Current is null) + { + return default!; + } + + return GetUpdateFromResult(Current); + } + } + + #endregion + + // Methods used by convenience implementation + private ClientResult GetUpdateFromResult(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + ThreadRun run = ThreadRun.FromResponse(response); + return ClientResult.FromValue(run, response); + } +} diff --git a/src/To.Be.Generated/StreamingRunOperation.cs b/src/To.Be.Generated/StreamingRunOperation.cs new file mode 100644 index 00000000..d47542fe --- /dev/null +++ b/src/To.Be.Generated/StreamingRunOperation.cs @@ -0,0 +1,280 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.Assistants; + +// Streaming version +public partial class StreamingRunOperation : RunOperation +{ + private readonly Func> _createRunAsync; + private readonly Func _createRun; + + + private StreamingRunOperationUpdateEnumerator? _enumerator; + + internal StreamingRunOperation( + ClientPipeline pipeline, + Uri endpoint, + + // Note if we pass funcs we don't need to pass in the pipeline. + Func> createRunAsync, + Func createRun) + : base(pipeline, endpoint) + { + _createRunAsync = createRunAsync; + _createRun = createRun; + } + + // TODO: this duplicates a field on the base type. Address? + public override bool IsCompleted { get; protected set; } + + public override async Task WaitUntilStoppedAsync(CancellationToken cancellationToken = default) + { + // TODO: add validation that stream is only requested and enumerated once. + // TODO: Make sure you can't create the same run twice and/or submit tools twice + // somehow, even accidentally. + + await foreach (StreamingUpdate update in GetUpdatesStreamingAsync(cancellationToken).ConfigureAwait(false)) + { + // Should terminate naturally when get to "requires action" because + // the SSE stream will end. + } + } + + public override void WaitUntilStopped(CancellationToken cancellationToken = default) + { + foreach (StreamingUpdate update in GetUpdatesStreaming(cancellationToken)) + { + // Should terminate naturally when get to "requires action" because + // the SSE stream will end. + } + } + + // Public APIs specific to streaming LRO + public virtual async IAsyncEnumerable GetUpdatesStreamingAsync( + [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + try + { + if (_enumerator is null) + { + AsyncStreamingUpdateCollection updates = new AsyncStreamingUpdateCollection(_createRunAsync); + _enumerator = new StreamingRunOperationUpdateEnumerator(updates); + } + + while (await _enumerator.MoveNextAsync().ConfigureAwait(false)) + { + if (_enumerator.Current is RunUpdate update) + { + ApplyUpdate(update); + } + + cancellationToken.ThrowIfCancellationRequested(); + + yield return _enumerator.Current; + } + } + finally + { + if (_enumerator != null) + { + await _enumerator.DisposeAsync(); + _enumerator = null; + } + } + } + + public virtual IEnumerable GetUpdatesStreaming(CancellationToken cancellationToken = default) + { + try + { + if (_enumerator is null) + { + StreamingUpdateCollection updates = new StreamingUpdateCollection(_createRun); + _enumerator = new StreamingRunOperationUpdateEnumerator(updates); + } + + while (_enumerator.MoveNext()) + { + if (_enumerator.Current is RunUpdate update) + { + ApplyUpdate(update); + } + + cancellationToken.ThrowIfCancellationRequested(); + + yield return _enumerator.Current; + } + } + finally + { + if (_enumerator != null) + { + _enumerator.Dispose(); + _enumerator = null; + } + } + } + + public override async IAsyncEnumerable GetUpdatesAsync(TimeSpan? pollingInterval = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) + { + if (pollingInterval is not null) + { + throw new NotSupportedException("Cannot specify polling interval for streaming operation."); + } + + await foreach (StreamingUpdate update in GetUpdatesStreamingAsync(cancellationToken).ConfigureAwait(false)) + { + if (update is RunUpdate runUpdate) + { + yield return runUpdate; + } + } + } + + public override IEnumerable GetUpdates(TimeSpan? pollingInterval = null, CancellationToken cancellationToken = default) + { + if (pollingInterval is not null) + { + throw new NotSupportedException("Cannot specify polling interval for streaming operation."); + } + + foreach (StreamingUpdate update in GetUpdatesStreaming()) + { + if (update is RunUpdate runUpdate) + { + yield return runUpdate; + } + } + } + + private void ApplyUpdate(ThreadRun update) + { + RunId ??= update.Id; + ThreadId ??= update.ThreadId; + + Value = update; + Status = update.Status; + IsCompleted = update.Status.IsTerminal; + + SetRawResponse(_enumerator!.GetRawResponse()); + } + + public virtual async Task SubmitToolOutputsToRunStreamingAsync( + IEnumerable toolOutputs, + CancellationToken cancellationToken = default) + { + if (ThreadId is null || RunId is null) + { + throw new InvalidOperationException("Cannot submit tools until first update stream has been applied."); + } + + BinaryContent content = new InternalSubmitToolOutputsRunRequest( + toolOutputs.ToList(), stream: true, null).ToBinaryContent(); + + // TODO: can we do this the same way as this in the other method instead + // of having to take all those funcs? + async Task getResultAsync() => + await SubmitToolOutputsToRunAsync(ThreadId, RunId, content, cancellationToken.ToRequestOptions(streaming: true)) + .ConfigureAwait(false); + + AsyncStreamingUpdateCollection updates = new AsyncStreamingUpdateCollection(getResultAsync); + if (_enumerator is null) + { + _enumerator = new StreamingRunOperationUpdateEnumerator(updates); + } + else + { + await _enumerator.ReplaceUpdateCollectionAsync(updates).ConfigureAwait(false); + } + } + + public virtual void SubmitToolOutputsToRunStreaming( + IEnumerable toolOutputs, + CancellationToken cancellationToken = default) + { + if (ThreadId is null || RunId is null) + { + throw new InvalidOperationException("Cannot submit tools until first update stream has been applied."); + } + + if (_enumerator is null) + { + throw new InvalidOperationException( + "Cannot submit tools until first run update stream has been enumerated. " + + "Call 'Wait' or 'GetUpdatesStreaming' to read update stream."); + } + + BinaryContent content = new InternalSubmitToolOutputsRunRequest( + toolOutputs.ToList(), stream: true, null).ToBinaryContent(); + + // TODO: can we do this the same way as this in the other method instead + // of having to take all those funcs? + ClientResult getResult() => + SubmitToolOutputsToRun(ThreadId, RunId, content, cancellationToken.ToRequestOptions(streaming: true)); + + StreamingUpdateCollection updates = new StreamingUpdateCollection(getResult); + if (_enumerator is null) + { + _enumerator = new StreamingRunOperationUpdateEnumerator(updates); + } + else + { + _enumerator.ReplaceUpdateCollection(updates); + } + } + + #region hide + + //// used to defer first request. + //internal virtual async Task CreateRunAsync(string threadId, BinaryContent content, RequestOptions? options = null) + //{ + // Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + // Argument.AssertNotNull(content, nameof(content)); + + // PipelineMessage? message = null; + // try + // { + // message = CreateCreateRunRequest(threadId, content, options); + // return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + // } + // finally + // { + // if (options?.BufferResponse != false) + // { + // message?.Dispose(); + // } + // } + //} + + //internal PipelineMessage CreateCreateRunRequest(string threadId, BinaryContent content, RequestOptions? options) + //{ + // var message = Pipeline.CreateMessage(); + // message.ResponseClassifier = PipelineMessageClassifier200; + // var request = message.Request; + // request.Method = "POST"; + // var uri = new ClientUriBuilder(); + // uri.Reset(_endpoint); + // uri.AppendPath("/threads/", false); + // uri.AppendPath(threadId, true); + // uri.AppendPath("/runs", false); + // request.Uri = uri.ToUri(); + // request.Headers.Set("Accept", "application/json"); + // request.Headers.Set("Content-Type", "application/json"); + // request.Content = content; + // message.Apply(options); + // return message; + //} + + //private static PipelineMessageClassifier? _pipelineMessageClassifier200; + //private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); + #endregion +} diff --git a/src/To.Be.Generated/StreamingRunOperationUpdateEnumerator.cs b/src/To.Be.Generated/StreamingRunOperationUpdateEnumerator.cs new file mode 100644 index 00000000..93a933cb --- /dev/null +++ b/src/To.Be.Generated/StreamingRunOperationUpdateEnumerator.cs @@ -0,0 +1,145 @@ +using System; +using System.ClientModel.Primitives; +using System.Collections; +using System.Collections.Generic; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.Assistants; + +internal partial class StreamingRunOperationUpdateEnumerator : + IAsyncEnumerator, + IEnumerator +{ + private StreamingUpdate? _current; + + private AsyncStreamingUpdateCollection? _asyncUpdates; + private IAsyncEnumerator? _asyncEnumerator; + + private StreamingUpdateCollection? _updates; + private IEnumerator? _enumerator; + + public StreamingRunOperationUpdateEnumerator( + AsyncStreamingUpdateCollection updates) + { + _asyncUpdates = updates; + } + + public StreamingRunOperationUpdateEnumerator( + StreamingUpdateCollection updates) + { + _updates = updates; + } + + // Cache this here for now + public PipelineResponse GetRawResponse() => + _asyncUpdates?.GetRawResponse() ?? + _updates?.GetRawResponse() ?? + throw new InvalidOperationException("No response available."); + + public StreamingUpdate Current => _current!; + + #region IEnumerator methods + + object IEnumerator.Current => _current!; + + public bool MoveNext() + { + if (_updates is null) + { + throw new InvalidOperationException("Cannot MoveNext after starting enumerator asynchronously."); + } + + _enumerator ??= _updates.GetEnumerator(); + + bool movedNext = _enumerator.MoveNext(); + _current = _enumerator.Current; + return movedNext; + } + + void IEnumerator.Reset() + { + throw new NotSupportedException("Cannot reset streaming enumerator."); + } + + public void Dispose() + { + if (_enumerator != null) + { + _enumerator.Dispose(); + _enumerator = null; + } + } + + #endregion + + #region IAsyncEnumerator methods + + public async ValueTask MoveNextAsync() + { + if (_asyncUpdates is null) + { + throw new InvalidOperationException("Cannot MoveNextAsync after starting enumerator synchronously."); + } + + _asyncEnumerator ??= _asyncUpdates.GetAsyncEnumerator(); + + bool movedNext = await _asyncEnumerator.MoveNextAsync().ConfigureAwait(false); + _current = _asyncEnumerator.Current; + return movedNext; + } + + public async ValueTask DisposeAsync() + { + // TODO: implement according to pattern + + if (_asyncEnumerator is null) + { + return; + } + + await _asyncEnumerator.DisposeAsync().ConfigureAwait(false); + } + + #endregion + + public async Task ReplaceUpdateCollectionAsync(AsyncStreamingUpdateCollection updates) + { + if (_asyncUpdates is null) + { + throw new InvalidOperationException("Cannot replace null update collection."); + } + + if (_updates is not null || _enumerator is not null) + { + throw new InvalidOperationException("Cannot being enumerating asynchronously after enumerating synchronously."); + } + + if (_asyncEnumerator is not null) + { + await _asyncEnumerator.DisposeAsync().ConfigureAwait(false); + _asyncEnumerator = null; + } + + _asyncUpdates = updates; + } + + public void ReplaceUpdateCollection(StreamingUpdateCollection updates) + { + if (_updates is null) + { + throw new InvalidOperationException("Cannot replace null update collection."); + } + + if (_asyncUpdates is not null || _asyncEnumerator is not null) + { + throw new InvalidOperationException("Cannot being enumerating synchronously after enumerating asynchronously."); + } + + _enumerator?.Dispose(); + _enumerator = null; + + _updates = updates; + } +} diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs b/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs new file mode 100644 index 00000000..c95cec02 --- /dev/null +++ b/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs @@ -0,0 +1,343 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.VectorStores; + +// Protocol version +public partial class VectorStoreFileBatchOperation : OperationResult +{ + private readonly ClientPipeline _pipeline; + private readonly Uri _endpoint; + + private readonly string _vectorStoreId; + private readonly string _batchId; + + private PollingInterval _pollingInterval; + + // For use with protocol methods where the response has been obtained prior + // to creation of the LRO instance. + internal VectorStoreFileBatchOperation( + ClientPipeline pipeline, + Uri endpoint, + string vectorStoreId, + string batchId, + string status, + PipelineResponse response) + : base(response) + { + _pipeline = pipeline; + _endpoint = endpoint; + + _vectorStoreId = vectorStoreId; + _batchId = batchId; + + IsCompleted = GetIsCompleted(status); + + _pollingInterval = new(); + + RehydrationToken = new VectorStoreFileBatchOperationToken(vectorStoreId, batchId); + } + + public override ContinuationToken? RehydrationToken { get; protected set; } + + public override bool IsCompleted { get; protected set; } + + // These are replaced when LRO is evolved to have conveniences + //public override async Task WaitAsync(CancellationToken cancellationToken = default) + //{ + // IAsyncEnumerator enumerator = + // new VectorStoreFileBatchOperationUpdateEnumerator( + // _pipeline, _endpoint, _vectorStoreId, _batchId, _options); + + // while (await enumerator.MoveNextAsync().ConfigureAwait(false)) + // { + // ApplyUpdate(enumerator.Current); + + // cancellationToken.ThrowIfCancellationRequested(); + + // // TODO: Plumb through cancellation token + // await _pollingInterval.WaitAsync(); + // } + //} + + //public override void Wait(CancellationToken cancellationToken = default) + //{ + // IEnumerator enumerator = + // new VectorStoreFileBatchOperationUpdateEnumerator( + // _pipeline, _endpoint, _vectorStoreId, _batchId, _options); + + // while (enumerator.MoveNext()) + // { + // ApplyUpdate(enumerator.Current); + + // cancellationToken.ThrowIfCancellationRequested(); + + // _pollingInterval.Wait(); + // } + //} + + private void ApplyUpdate(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string? status = doc.RootElement.GetProperty("status"u8).GetString(); + + IsCompleted = GetIsCompleted(status); + SetRawResponse(response); + } + + private static bool GetIsCompleted(string? status) + { + return status == "completed" || + status == "cancelled" || + status == "failed"; + } + + // Generated protocol methods + + /// + /// [Protocol Method] Retrieves a vector store file batch. + /// + /// The ID of the vector store that the file batch belongs to. + /// The ID of the file batch being retrieved. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task GetBatchFileJobAsync(string vectorStoreId, string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(vectorStoreId, batchId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Retrieves a vector store file batch. + /// + /// The ID of the vector store that the file batch belongs to. + /// The ID of the file batch being retrieved. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult GetBatchFileJob(string vectorStoreId, string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(vectorStoreId, batchId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Cancel a vector store file batch. This attempts to cancel the processing of files in this batch as soon as possible. + /// + /// The ID of the vector store that the file batch belongs to. + /// The ID of the file batch to cancel. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task CancelBatchFileJobAsync(string vectorStoreId, string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateCancelVectorStoreFileBatchRequest(vectorStoreId, batchId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Cancel a vector store file batch. This attempts to cancel the processing of files in this batch as soon as possible. + /// + /// The ID of the vector store that the file batch belongs to. + /// The ID of the file batch to cancel. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult CancelBatchFileJob(string vectorStoreId, string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateCancelVectorStoreFileBatchRequest(vectorStoreId, batchId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Returns a paginated collection of vector store files in a batch. + /// + /// The ID of the vector store that the file batch belongs to. + /// The ID of the file batch that the files belong to. + /// + /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the + /// default is 20. + /// + /// + /// Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and`desc` + /// for descending order. Allowed values: "asc" | "desc" + /// + /// + /// A cursor for use in pagination. `after` is an object ID that defines your place in the list. + /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + /// subsequent call can include after=obj_foo in order to fetch the next page of the list. + /// + /// + /// A cursor for use in pagination. `before` is an object ID that defines your place in the list. + /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + /// subsequent call can include before=obj_foo in order to fetch the previous page of the list. + /// + /// Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// A collection of service responses, each holding a page of values. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual IAsyncEnumerable GetFileAssociationsAsync(string vectorStoreId, string batchId, int? limit, string order, string after, string before, string filter, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + VectorStoreFileBatchesPageEnumerator enumerator = new VectorStoreFileBatchesPageEnumerator(_pipeline, _endpoint, vectorStoreId, batchId, limit, order, after, before, filter, options); + return PageCollectionHelpers.CreateAsync(enumerator); + } + + /// + /// [Protocol Method] Returns a paginated collection of vector store files in a batch. + /// + /// The ID of the vector store that the file batch belongs to. + /// The ID of the file batch that the files belong to. + /// + /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the + /// default is 20. + /// + /// + /// Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and`desc` + /// for descending order. Allowed values: "asc" | "desc" + /// + /// + /// A cursor for use in pagination. `after` is an object ID that defines your place in the list. + /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + /// subsequent call can include after=obj_foo in order to fetch the next page of the list. + /// + /// + /// A cursor for use in pagination. `before` is an object ID that defines your place in the list. + /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + /// subsequent call can include before=obj_foo in order to fetch the previous page of the list. + /// + /// Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// A collection of service responses, each holding a page of values. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual IEnumerable GetFileAssociations(string vectorStoreId, string batchId, int? limit, string order, string after, string before, string filter, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + VectorStoreFileBatchesPageEnumerator enumerator = new VectorStoreFileBatchesPageEnumerator(_pipeline, _endpoint, vectorStoreId, batchId, limit, order, after, before, filter, options); + return PageCollectionHelpers.Create(enumerator); + } + + internal PipelineMessage CreateGetVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/vector_stores/", false); + uri.AppendPath(vectorStoreId, true); + uri.AppendPath("/file_batches/", false); + uri.AppendPath(batchId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateCancelVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "POST"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/vector_stores/", false); + uri.AppendPath(vectorStoreId, true); + uri.AppendPath("/file_batches/", false); + uri.AppendPath(batchId, true); + uri.AppendPath("/cancel", false); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateGetFilesInVectorStoreBatchesRequest(string vectorStoreId, string batchId, int? limit, string order, string after, string before, string filter, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/vector_stores/", false); + uri.AppendPath(vectorStoreId, true); + uri.AppendPath("/file_batches/", false); + uri.AppendPath(batchId, true); + uri.AppendPath("/files", false); + if (limit != null) + { + uri.AppendQuery("limit", limit.Value, true); + } + if (order != null) + { + uri.AppendQuery("order", order, true); + } + if (after != null) + { + uri.AppendQuery("after", after, true); + } + if (before != null) + { + uri.AppendQuery("before", before, true); + } + if (filter != null) + { + uri.AppendQuery("filter", filter, true); + } + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); +} \ No newline at end of file diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperation.cs b/src/To.Be.Generated/VectorStoreFileBatchOperation.cs new file mode 100644 index 00000000..e6a3e6bf --- /dev/null +++ b/src/To.Be.Generated/VectorStoreFileBatchOperation.cs @@ -0,0 +1,291 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.VectorStores; + +// Convenience version +public partial class VectorStoreFileBatchOperation : OperationResult +{ + // Convenience version + internal VectorStoreFileBatchOperation( + ClientPipeline pipeline, + Uri endpoint, + ClientResult result) + : base(result.GetRawResponse()) + { + _pipeline = pipeline; + _endpoint = endpoint; + + Value = result; + Status = Value.Status; + IsCompleted = GetIsCompleted(Value.Status); + + _vectorStoreId = Value.VectorStoreId; + _batchId = Value.BatchId; + + _pollingInterval = new(); + + RehydrationToken = new VectorStoreFileBatchOperationToken(VectorStoreId, BatchId); + } + + // TODO: interesting question regarding whether these properties should be + // nullable or not. If someone has called the protocol method, do they want + // to pay the perf cost of deserialization? This could capitalize on a + // property on RequestOptions that allows the caller to opt-in to creation + // of convenience models. For now, make them nullable so I don't have to + // pass the model into the constructor from a protocol method. + public VectorStoreBatchFileJob? Value { get; private set; } + public VectorStoreBatchFileJobStatus? Status { get; private set; } + + public string VectorStoreId { get => _vectorStoreId; } + public string BatchId { get => _batchId; } + + public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) + { + IAsyncEnumerator> enumerator = + new VectorStoreFileBatchOperationUpdateEnumerator( + _pipeline, _endpoint, _vectorStoreId, _batchId, cancellationToken); + + while (await enumerator.MoveNextAsync().ConfigureAwait(false)) + { + ApplyUpdate(enumerator.Current); + + await _pollingInterval.WaitAsync(cancellationToken); + } + } + + public override void WaitForCompletion(CancellationToken cancellationToken = default) + { + IEnumerator> enumerator = + new VectorStoreFileBatchOperationUpdateEnumerator( + _pipeline, _endpoint, _vectorStoreId, _batchId, cancellationToken); + + while (enumerator.MoveNext()) + { + ApplyUpdate(enumerator.Current); + + cancellationToken.ThrowIfCancellationRequested(); + + _pollingInterval.Wait(); + } + } + + private void ApplyUpdate(ClientResult update) + { + Value = update; + Status = Value.Status; + + IsCompleted = GetIsCompleted(Value.Status); + SetRawResponse(update.GetRawResponse()); + } + + private static bool GetIsCompleted(VectorStoreBatchFileJobStatus status) + { + return status == VectorStoreBatchFileJobStatus.Completed || + status == VectorStoreBatchFileJobStatus.Cancelled || + status == VectorStoreBatchFileJobStatus.Failed; + } + + // Generated convenience methods + + /// + /// Gets an existing vector store batch file ingestion job from a known vector store ID and job ID. + /// + /// A token that can be used to cancel this method call. + /// A instance representing the ingestion operation. + public virtual async Task> GetBatchFileJobAsync(CancellationToken cancellationToken = default) + { + ClientResult result = await GetBatchFileJobAsync(_vectorStoreId, _batchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); + return ClientResult.FromValue(value, response); + } + + /// + /// Gets an existing vector store batch file ingestion job from a known vector store ID and job ID. + /// + /// A token that can be used to cancel this method call. + /// A instance representing the ingestion operation. + public virtual ClientResult GetBatchFileJob(CancellationToken cancellationToken = default) + { + ClientResult result = GetBatchFileJob(_vectorStoreId, _batchId, cancellationToken.ToRequestOptions()); + PipelineResponse response = result.GetRawResponse(); + VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); + return ClientResult.FromValue(value, response); + } + + /// + /// Cancels an in-progress . + /// + /// A token that can be used to cancel this method call. + /// An updated instance. + public virtual async Task> CancelBatchFileJobAsync(CancellationToken cancellationToken = default) + { + ClientResult result = await CancelBatchFileJobAsync(_vectorStoreId, _batchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); + return ClientResult.FromValue(value, response); + } + + /// + /// Cancels an in-progress . + /// + /// A token that can be used to cancel this method call. + /// An updated instance. + public virtual ClientResult CancelBatchFileJob(CancellationToken cancellationToken = default) + { + ClientResult result = CancelBatchFileJob(_vectorStoreId, _batchId, cancellationToken.ToRequestOptions()); + PipelineResponse response = result.GetRawResponse(); + VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); + return ClientResult.FromValue(value, response); + } + + /// + /// Gets a page collection of file associations associated with a vector store batch file job, representing the files + /// that were scheduled for ingestion into the vector store. + /// + /// Options describing the collection to return. + /// A token that can be used to cancel this method call. + /// holds pages of values. To obtain a collection of values, call + /// . To obtain the current + /// page of values, call . + /// A collection of pages of . + public virtual AsyncPageCollection GetFileAssociationsAsync( + VectorStoreFileAssociationCollectionOptions? options = default, + CancellationToken cancellationToken = default) + { + VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, + _vectorStoreId, + _batchId, + options?.PageSize, + options?.Order?.ToString(), + options?.AfterId, + options?.BeforeId, + options?.Filter?.ToString(), + cancellationToken.ToRequestOptions()); + + return PageCollectionHelpers.CreateAsync(enumerator); + } + + /// + /// Rehydrates a page collection of file associations from a page token. + /// + /// Page token corresponding to the first page of the collection to rehydrate. + /// A token that can be used to cancel this method call. + /// holds pages of values. To obtain a collection of values, call + /// . To obtain the current + /// page of values, call . + /// A collection of pages of . + public virtual AsyncPageCollection GetFileAssociationsAsync( + ContinuationToken firstPageToken, + CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); + + VectorStoreFileBatchesPageToken pageToken = VectorStoreFileBatchesPageToken.FromToken(firstPageToken); + + if (_vectorStoreId != pageToken.VectorStoreId) + { + throw new ArgumentException( + "Invalid page token. 'VectorStoreId' value does not match page token value.", + nameof(firstPageToken)); + } + + if (_batchId != pageToken.BatchId) + { + throw new ArgumentException( + "Invalid page token. 'BatchId' value does not match page token value.", + nameof(firstPageToken)); + } + + VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, + pageToken.VectorStoreId, + pageToken.BatchId, + pageToken.Limit, + pageToken.Order, + pageToken.After, + pageToken.Before, + pageToken.Filter, + cancellationToken.ToRequestOptions()); + + return PageCollectionHelpers.CreateAsync(enumerator); + } + + /// + /// Gets a page collection of file associations associated with a vector store batch file job, representing the files + /// that were scheduled for ingestion into the vector store. + /// + /// Options describing the collection to return. + /// A token that can be used to cancel this method call. + /// holds pages of values. To obtain a collection of values, call + /// . To obtain the current + /// page of values, call . + /// A collection of pages of . + public virtual PageCollection GetFileAssociations( + VectorStoreFileAssociationCollectionOptions? options = default, + CancellationToken cancellationToken = default) + { + VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, + _vectorStoreId, + _batchId, + options?.PageSize, + options?.Order?.ToString(), + options?.AfterId, + options?.BeforeId, + options?.Filter?.ToString(), + cancellationToken.ToRequestOptions()); + + return PageCollectionHelpers.Create(enumerator); + } + + /// + /// Rehydrates a page collection of file associations from a page token. + /// that were scheduled for ingestion into the vector store. + /// + /// Page token corresponding to the first page of the collection to rehydrate. + /// A token that can be used to cancel this method call. + /// holds pages of values. To obtain a collection of values, call + /// . To obtain the current + /// page of values, call . + /// A collection of pages of . + public virtual PageCollection GetFileAssociations( + ContinuationToken firstPageToken, + CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); + + VectorStoreFileBatchesPageToken pageToken = VectorStoreFileBatchesPageToken.FromToken(firstPageToken); + + if (_vectorStoreId != pageToken.VectorStoreId) + { + throw new ArgumentException( + "Invalid page token. 'VectorStoreId' value does not match page token value.", + nameof(firstPageToken)); + } + + if (_batchId != pageToken.BatchId) + { + throw new ArgumentException( + "Invalid page token. 'BatchId' value does not match page token value.", + nameof(firstPageToken)); + } + + VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, + pageToken.VectorStoreId, + pageToken.BatchId, + pageToken.Limit, + pageToken.Order, + pageToken.After, + pageToken.Before, + pageToken.Filter, + cancellationToken.ToRequestOptions()); + + return PageCollectionHelpers.Create(enumerator); + } +} \ No newline at end of file diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperationToken.cs b/src/To.Be.Generated/VectorStoreFileBatchOperationToken.cs new file mode 100644 index 00000000..bcda6b72 --- /dev/null +++ b/src/To.Be.Generated/VectorStoreFileBatchOperationToken.cs @@ -0,0 +1,101 @@ +using System; +using System.ClientModel; +using System.Diagnostics; +using System.IO; +using System.Text.Json; + +#nullable enable + +namespace OpenAI.VectorStores; + +internal class VectorStoreFileBatchOperationToken : ContinuationToken +{ + public VectorStoreFileBatchOperationToken(string vectorStoreId, string batchId) + { + VectorStoreId = vectorStoreId; + BatchId = batchId; + } + + public string VectorStoreId { get; } + + public string BatchId { get; } + + public override BinaryData ToBytes() + { + using MemoryStream stream = new(); + using Utf8JsonWriter writer = new(stream); + writer.WriteStartObject(); + + writer.WriteString("vectorStoreId", VectorStoreId); + writer.WriteString("batchId", BatchId); + + writer.WriteEndObject(); + + writer.Flush(); + stream.Position = 0; + + return BinaryData.FromStream(stream); + } + + public static VectorStoreFileBatchOperationToken FromToken(ContinuationToken continuationToken) + { + if (continuationToken is VectorStoreFileBatchOperationToken token) + { + return token; + } + + BinaryData data = continuationToken.ToBytes(); + + if (data.ToMemory().Length == 0) + { + throw new ArgumentException("Failed to create VectorStoreFileBatchOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + Utf8JsonReader reader = new(data); + + string vectorStoreId = null!; + string batchId = null!; + + reader.Read(); + + Debug.Assert(reader.TokenType == JsonTokenType.StartObject); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); + + string propertyName = reader.GetString()!; + + switch (propertyName) + { + case "vectorStoreId": + reader.Read(); + Debug.Assert(reader.TokenType == JsonTokenType.String); + vectorStoreId = reader.GetString()!; + break; + + case "batchId": + reader.Read(); + Debug.Assert(reader.TokenType == JsonTokenType.String); + batchId = reader.GetString()!; + break; + + default: + throw new JsonException($"Unrecognized property '{propertyName}'."); + } + } + + if (vectorStoreId is null || batchId is null) + { + throw new ArgumentException("Failed to create VectorStoreFileBatchOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + return new(vectorStoreId, batchId); + } +} + diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.Protocol.cs b/src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.Protocol.cs new file mode 100644 index 00000000..bf3b1f1a --- /dev/null +++ b/src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.Protocol.cs @@ -0,0 +1,175 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.VectorStores; + +internal partial class VectorStoreFileBatchOperationUpdateEnumerator : + IAsyncEnumerator, + IEnumerator +{ + private readonly ClientPipeline _pipeline; + private readonly Uri _endpoint; + private readonly CancellationToken _cancellationToken; + + private readonly string _vectorStoreId; + private readonly string _batchId; + + private ClientResult? _current; + private bool _hasNext = true; + + public VectorStoreFileBatchOperationUpdateEnumerator( + ClientPipeline pipeline, + Uri endpoint, + string vectorStoreId, + string batchId, + CancellationToken cancellationToken) + { + _pipeline = pipeline; + _endpoint = endpoint; + + _vectorStoreId = vectorStoreId; + _batchId = batchId; + + _cancellationToken = cancellationToken; + } + + public ClientResult Current => _current!; + + #region IEnumerator methods + + object IEnumerator.Current => _current!; + + bool IEnumerator.MoveNext() + { + if (!_hasNext) + { + _current = null; + return false; + } + + ClientResult result = GetBatchFileJob(_vectorStoreId, _batchId, _cancellationToken.ToRequestOptions()); + + _current = result; + _hasNext = HasNext(result); + + return true; + } + + void IEnumerator.Reset() => _current = null; + + void IDisposable.Dispose() { } + + #endregion + + #region IAsyncEnumerator methods + + ClientResult IAsyncEnumerator.Current => _current!; + + public async ValueTask MoveNextAsync() + { + if (!_hasNext) + { + _current = null; + return false; + } + + ClientResult result = await GetBatchFileJobAsync(_vectorStoreId, _batchId, _cancellationToken.ToRequestOptions()).ConfigureAwait(false); + + _current = result; + _hasNext = HasNext(result); + + return true; + } + + // TODO: handle Dispose and DisposeAsync using proper patterns? + ValueTask IAsyncDisposable.DisposeAsync() => default; + + #endregion + + private bool HasNext(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + + // TODO: don't parse JsonDocument twice if possible + using JsonDocument doc = JsonDocument.Parse(response.Content); + string? status = doc.RootElement.GetProperty("status"u8).GetString(); + + bool isComplete = status == "completed" || + status == "cancelled" || + status == "failed"; + + return !isComplete; + } + + // Generated methods + + /// + /// [Protocol Method] Retrieves a vector store file batch. + /// + /// The ID of the vector store that the file batch belongs to. + /// The ID of the file batch being retrieved. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task GetBatchFileJobAsync(string vectorStoreId, string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(vectorStoreId, batchId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Retrieves a vector store file batch. + /// + /// The ID of the vector store that the file batch belongs to. + /// The ID of the file batch being retrieved. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult GetBatchFileJob(string vectorStoreId, string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(vectorStoreId, batchId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + internal PipelineMessage CreateGetVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/vector_stores/", false); + uri.AppendPath(vectorStoreId, true); + uri.AppendPath("/file_batches/", false); + uri.AppendPath(batchId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); +} diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.cs b/src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.cs new file mode 100644 index 00000000..c901c63d --- /dev/null +++ b/src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.cs @@ -0,0 +1,54 @@ +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; + +#nullable enable + +namespace OpenAI.VectorStores; + +internal partial class VectorStoreFileBatchOperationUpdateEnumerator : + IAsyncEnumerator>, + IEnumerator> +{ + #region IEnumerator> methods + + ClientResult IEnumerator>.Current + { + get + { + if (Current is null) + { + return default!; + } + + return GetUpdateFromResult(Current); + } + } + + #endregion + + #region IAsyncEnumerator> methods + + ClientResult IAsyncEnumerator>.Current + { + get + { + if (Current is null) + { + return default!; + } + + return GetUpdateFromResult(Current); + } + } + + #endregion + + // Methods used by convenience implementation + private ClientResult GetUpdateFromResult(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + VectorStoreBatchFileJob run = VectorStoreBatchFileJob.FromResponse(response); + return ClientResult.FromValue(run, response); + } +} diff --git a/tests/Assistants/VectorStoreTests.cs b/tests/Assistants/VectorStoreTests.cs index ea1d2b7a..cc12ebe1 100644 --- a/tests/Assistants/VectorStoreTests.cs +++ b/tests/Assistants/VectorStoreTests.cs @@ -271,22 +271,19 @@ public void CanUseBatchIngestion() IReadOnlyList testFiles = GetNewTestFiles(5); - VectorStoreBatchFileJob batchJob = client.CreateBatchFileJob(vectorStore, testFiles); - Validate(batchJob); + VectorStoreFileBatchOperation batchOperation = client.CreateBatchFileJob(ReturnWhen.Started, vectorStore, testFiles); + Validate(batchOperation); Assert.Multiple(() => { - Assert.That(batchJob.BatchId, Is.Not.Null); - Assert.That(batchJob.VectorStoreId, Is.EqualTo(vectorStore.Id)); - Assert.That(batchJob.Status, Is.EqualTo(VectorStoreBatchFileJobStatus.InProgress)); + Assert.That(batchOperation.BatchId, Is.Not.Null); + Assert.That(batchOperation.VectorStoreId, Is.EqualTo(vectorStore.Id)); + Assert.That(batchOperation.Status, Is.EqualTo(VectorStoreBatchFileJobStatus.InProgress)); }); - for (int i = 0; i < 10 && client.GetBatchFileJob(batchJob).Value.Status != VectorStoreBatchFileJobStatus.Completed; i++) - { - Thread.Sleep(500); - } + batchOperation.WaitForCompletion(); - foreach (VectorStoreFileAssociation association in client.GetFileAssociations(batchJob).GetAllValues()) + foreach (VectorStoreFileAssociation association in batchOperation.GetFileAssociations().GetAllValues()) { Assert.Multiple(() => { @@ -382,9 +379,9 @@ protected void Cleanup() { ErrorOptions = ClientErrorBehaviors.NoThrow, }; - foreach (VectorStoreBatchFileJob job in _jobsToCancel) + foreach (VectorStoreFileBatchOperation job in _jobsToCancel) { - ClientResult protocolResult = vectorStoreClient.CancelBatchFileJob(job.VectorStoreId, job.BatchId, requestOptions); + ClientResult protocolResult = job.CancelBatchFileJob(job.VectorStoreId, job.BatchId, requestOptions); Console.WriteLine($"Cleanup: {job.BatchId} => {protocolResult?.GetRawResponse()?.Status}"); } foreach (VectorStoreFileAssociation association in _associationsToRemove) @@ -413,7 +410,7 @@ protected void Cleanup() /// The provided instance type isn't supported. private void Validate(T target) { - if (target is VectorStoreBatchFileJob job) + if (target is VectorStoreFileBatchOperation job) { Assert.That(job.BatchId, Is.Not.Null); _jobsToCancel.Add(job); @@ -440,7 +437,7 @@ private void Validate(T target) } } - private readonly List _jobsToCancel = []; + private readonly List _jobsToCancel = []; private readonly List _associationsToRemove = []; private readonly List _filesToDelete = []; private readonly List _vectorStoresToDelete = []; diff --git a/tests/Batch/BatchTests.cs b/tests/Batch/BatchTests.cs index 16b7c5b4..1289d74a 100644 --- a/tests/Batch/BatchTests.cs +++ b/tests/Batch/BatchTests.cs @@ -75,11 +75,11 @@ public async Task CreateGetAndCancelBatchProtocol() testMetadataKey = "test metadata value", }, })); - ClientResult batchResult = IsAsync - ? await client.CreateBatchAsync(content) - : client.CreateBatch(content); + BatchOperation batchOperation = IsAsync + ? await client.CreateBatchAsync(ReturnWhen.Started, content) + : client.CreateBatch(ReturnWhen.Started, content); - BinaryData response = batchResult.GetRawResponse().Content; + BinaryData response = batchOperation.GetRawResponse().Content; JsonDocument jsonDocument = JsonDocument.Parse(response); JsonElement idElement = jsonDocument.RootElement.GetProperty("id"); @@ -100,18 +100,14 @@ public async Task CreateGetAndCancelBatchProtocol() Assert.That(status, Is.EqualTo("validating")); Assert.That(testMetadataKey, Is.EqualTo("test metadata value")); - batchResult = IsAsync - ? await client.GetBatchAsync(id, options: null) - : client.GetBatch(id, options: null); - JsonElement endpointElement = jsonDocument.RootElement.GetProperty("endpoint"); string endpoint = endpointElement.GetString(); Assert.That(endpoint, Is.EqualTo("/v1/chat/completions")); - batchResult = IsAsync - ? await client.CancelBatchAsync(id, options: null) - : client.CancelBatch(id, options: null); + ClientResult clientResult = IsAsync + ? await batchOperation.CancelBatchAsync(id, options: null) + : batchOperation.CancelBatch(id, options: null); statusElement = jsonDocument.RootElement.GetProperty("status"); status = statusElement.GetString(); diff --git a/tests/FineTuning/FineTuningTests.cs b/tests/FineTuning/FineTuningTests.cs new file mode 100644 index 00000000..cf6d4d0d --- /dev/null +++ b/tests/FineTuning/FineTuningTests.cs @@ -0,0 +1,89 @@ +using NUnit.Framework; +using OpenAI.Files; +using OpenAI.FineTuning; +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using static OpenAI.Tests.TestHelpers; + +namespace OpenAI.Tests.FineTuning; + +#pragma warning disable OPENAI001 + +[Parallelizable(ParallelScope.Fixtures)] +public partial class FineTuningTests +{ + [Test] + public void BasicFineTuningOperationsWork() + { + // Upload training file first + FileClient fileClient = GetTestClient(TestScenario.Files); + string filename = "toy_chat.jsonl"; + BinaryData fileContent = BinaryData.FromString(""" + {"messages": [{"role": "user", "content": "I lost my book today."}, {"role": "assistant", "content": "You can read everything on ebooks these days!"}]} + {"messages": [{"role": "system", "content": "You are a happy assistant that puts a positive spin on everything."}, {"role": "assistant", "content": "You're great!"}]} + """); + OpenAIFileInfo uploadedFile = fileClient.UploadFile(fileContent, filename, FileUploadPurpose.FineTune); + Assert.That(uploadedFile?.Filename, Is.EqualTo(filename)); + + // Submit fine-tuning job + FineTuningClient client = GetTestClient(); + + string json = $"{{\"training_file\":\"{uploadedFile.Id}\",\"model\":\"gpt-3.5-turbo\"}}"; + BinaryData input = BinaryData.FromString(json); + using BinaryContent content = BinaryContent.Create(input); + + FineTuningOperation operation = client.CreateJob(ReturnWhen.Started, content); + } + + [OneTimeTearDown] + protected void Cleanup() + { + // Skip cleanup if there is no API key (e.g., if we are not running live tests). + if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("OPEN_API_KEY"))) + { + return; + } + + FileClient fileClient = new(); + RequestOptions requestOptions = new() + { + ErrorOptions = ClientErrorBehaviors.NoThrow, + }; + foreach (OpenAIFileInfo file in _filesToDelete) + { + Console.WriteLine($"Cleanup: {file.Id} -> {fileClient.DeleteFile(file.Id, requestOptions)?.GetRawResponse().Status}"); + } + _filesToDelete.Clear(); + } + + /// + /// Performs basic, invariant validation of a target that was just instantiated from its corresponding origination + /// mechanism. If applicable, the instance is recorded into the test run for cleanup of persistent resources. + /// + /// Instance type being validated. + /// The instance to validate. + /// The provided instance type isn't supported. + private void Validate(T target) + { + if (target is OpenAIFileInfo file) + { + Assert.That(file?.Id, Is.Not.Null); + _filesToDelete.Add(file); + } + else + { + throw new NotImplementedException($"{nameof(Validate)} helper not implemented for: {typeof(T)}"); + } + } + + private readonly List _filesToDelete = []; + + private static FineTuningClient GetTestClient() => GetTestClient(TestScenario.FineTuning); + + private static readonly DateTimeOffset s_2024 = new(2024, 1, 1, 0, 0, 0, TimeSpan.Zero); + private static readonly string s_cleanupMetadataKey = $"test_metadata_cleanup_eligible"; +} + +#pragma warning restore OPENAI001 diff --git a/tests/Utility/TestHelpers.cs b/tests/Utility/TestHelpers.cs index 9231231e..6ff1237a 100644 --- a/tests/Utility/TestHelpers.cs +++ b/tests/Utility/TestHelpers.cs @@ -5,6 +5,7 @@ using OpenAI.Chat; using OpenAI.Embeddings; using OpenAI.Files; +using OpenAI.FineTuning; using OpenAI.Images; using OpenAI.VectorStores; using System; @@ -54,6 +55,7 @@ public static T GetTestClient(TestScenario scenario, string overrideModel = n TestScenario.Chat => new ChatClient(overrideModel ?? "gpt-4o-mini", options), TestScenario.Embeddings => new EmbeddingClient(overrideModel ?? "text-embedding-3-small", options), TestScenario.Files => new FileClient(options), + TestScenario.FineTuning => new FineTuningClient(options), TestScenario.Images => new ImageClient(overrideModel ?? "dall-e-3", options), #pragma warning disable OPENAI001 TestScenario.VectorStores => new VectorStoreClient(options), From 93e6b007385d37ee56d504cd06c19d7dce0f2e0b Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Mon, 5 Aug 2024 14:41:30 -0700 Subject: [PATCH 02/14] misc tidy --- src/Custom/Batch/BatchClient.Protocol.cs | 6 +- .../FineTuning/FineTuningClient.Protocol.cs | 6 +- .../VectorStoreClient.Protocol.cs | 10 +- src/To.Be.Generated/RunOperation.Protocol.cs | 639 ------------------ src/To.Be.Generated/RunOperation.cs | 392 ----------- src/To.Be.Generated/RunOperationToken.cs | 102 --- .../RunOperationUpdateEnumerator.Protocol.cs | 175 ----- .../RunOperationUpdateEnumerator.cs | 54 -- src/To.Be.Generated/StreamingRunOperation.cs | 280 -------- .../StreamingRunOperationUpdateEnumerator.cs | 145 ---- 10 files changed, 16 insertions(+), 1793 deletions(-) delete mode 100644 src/To.Be.Generated/RunOperation.Protocol.cs delete mode 100644 src/To.Be.Generated/RunOperation.cs delete mode 100644 src/To.Be.Generated/RunOperationToken.cs delete mode 100644 src/To.Be.Generated/RunOperationUpdateEnumerator.Protocol.cs delete mode 100644 src/To.Be.Generated/RunOperationUpdateEnumerator.cs delete mode 100644 src/To.Be.Generated/StreamingRunOperation.cs delete mode 100644 src/To.Be.Generated/StreamingRunOperationUpdateEnumerator.cs diff --git a/src/Custom/Batch/BatchClient.Protocol.cs b/src/Custom/Batch/BatchClient.Protocol.cs index 321502ee..24f42025 100644 --- a/src/Custom/Batch/BatchClient.Protocol.cs +++ b/src/Custom/Batch/BatchClient.Protocol.cs @@ -10,7 +10,8 @@ public partial class BatchClient { public virtual async Task CreateBatchAsync( ReturnWhen returnWhen, - BinaryContent content, RequestOptions options = null) + BinaryContent content, + RequestOptions options = null) { Argument.AssertNotNull(content, nameof(content)); @@ -34,7 +35,8 @@ public virtual async Task CreateBatchAsync( public virtual BatchOperation CreateBatch( ReturnWhen returnWhen, - BinaryContent content, RequestOptions options = null) + BinaryContent content, + RequestOptions options = null) { Argument.AssertNotNull(content, nameof(content)); diff --git a/src/Custom/FineTuning/FineTuningClient.Protocol.cs b/src/Custom/FineTuning/FineTuningClient.Protocol.cs index 5c97e02d..a42379a9 100644 --- a/src/Custom/FineTuning/FineTuningClient.Protocol.cs +++ b/src/Custom/FineTuning/FineTuningClient.Protocol.cs @@ -37,7 +37,8 @@ public partial class FineTuningClient /// The response returned from the service. public virtual async Task CreateJobAsync( ReturnWhen returnWhen, - BinaryContent content, RequestOptions options = null) + BinaryContent content, + RequestOptions options = null) { Argument.AssertNotNull(content, nameof(content)); @@ -75,7 +76,8 @@ public virtual async Task CreateJobAsync( /// The response returned from the service. public virtual FineTuningOperation CreateJob( ReturnWhen returnWhen, - BinaryContent content, RequestOptions options = null) + BinaryContent content, + RequestOptions options = null) { Argument.AssertNotNull(content, nameof(content)); diff --git a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs index 4adcd361..b15bb30c 100644 --- a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs +++ b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs @@ -434,7 +434,11 @@ public virtual ClientResult RemoveFileFromStore(string vectorStoreId, string fil /// Service returned a non-success status code. /// The response returned from the service. [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task CreateBatchFileJobAsync(ReturnWhen returnWhen, string vectorStoreId, BinaryContent content, RequestOptions options = null) + public virtual async Task CreateBatchFileJobAsync( + ReturnWhen returnWhen, + string vectorStoreId, + BinaryContent content, + RequestOptions options = null) { Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); Argument.AssertNotNull(content, nameof(content)); @@ -469,7 +473,9 @@ public virtual async Task CreateBatchFileJobAsync [EditorBrowsable(EditorBrowsableState.Never)] public virtual VectorStoreFileBatchOperation CreateBatchFileJob( ReturnWhen returnWhen, - string vectorStoreId, BinaryContent content, RequestOptions options = null) + string vectorStoreId, + BinaryContent content, + RequestOptions options = null) { Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); Argument.AssertNotNull(content, nameof(content)); diff --git a/src/To.Be.Generated/RunOperation.Protocol.cs b/src/To.Be.Generated/RunOperation.Protocol.cs deleted file mode 100644 index 5d9b6c0e..00000000 --- a/src/To.Be.Generated/RunOperation.Protocol.cs +++ /dev/null @@ -1,639 +0,0 @@ -using System; -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Collections.Generic; -using System.ComponentModel; -using System.Text.Json; -using System.Threading.Tasks; - -#nullable enable - -namespace OpenAI.Assistants; - -// Protocol version -public partial class RunOperation : ClientResult -{ - private readonly ClientPipeline _pipeline; - private readonly Uri _endpoint; - - private string? _threadId; - private string? _runId; - private string? _status; - - private bool _isCompleted; - - private PollingInterval? _pollingInterval; - - // For use with protocol methods where the response has been obtained prior - // to creation of the LRO instance. - internal RunOperation( - ClientPipeline pipeline, - Uri endpoint, - PipelineResponse response) - : base(response) - { - _pipeline = pipeline; - _endpoint = endpoint; - - // Protocol method was called with stream=true option. - bool isStreaming = - response.Headers.TryGetValue("Content-Type", out string? contentType) && - contentType == "text/event-stream; charset=utf-8"; - - if (!isStreaming) - { - _pollingInterval = new(); - - using JsonDocument doc = JsonDocument.Parse(response.Content); - - _status = doc.RootElement.GetProperty("status"u8).GetString(); - _threadId = doc.RootElement.GetProperty("thread_id"u8).GetString(); - _runId = doc.RootElement.GetProperty("id"u8).GetString(); - - if (_status is null || _threadId is null || _runId is null) - { - throw new ArgumentException("Invalid 'response' body.", nameof(response)); - } - - IsCompleted = GetIsCompleted(_status!); - } - } - - #region OperationResult methods - - public virtual bool IsCompleted - { - get - { - // We need this check in the protocol/streaming case. - if (IsStreaming) - { - throw new NotSupportedException("Cannot obtain operation status from streaming operation."); - } - - return _isCompleted; - } - - protected set => _isCompleted = value; - } - - public virtual ContinuationToken? RehydrationToken { get; protected set; } - - internal bool IsStreaming => _pollingInterval == null; - - // Note: these work for protocol-only. - // Once convenience overloads available, these get replaced by those implementations. - - //public override Task WaitAsync(CancellationToken cancellationToken = default) - //{ - // if (_isStreaming) - // { - // // We would have to read from the stream to get the run ID to poll for. - // throw new NotSupportedException("Cannot poll for status updates from streaming operation."); - // } - - // // See: https://platform.openai.com/docs/assistants/how-it-works/polling-for-updates - - // IAsyncEnumerator enumerator = GetUpdateResultEnumeratorAsync(); - - // await while (await enumerator.MoveNextAsync().ConfigureAwait(false)) - // { - // ApplyUpdate(enumerator.Current); - - // // Don't keep polling if would do so infinitely. - // if (_status == "requires_action") - // { - // return; - // } - - // cancellationToken.ThrowIfCancellationRequested(); - - // await _pollingInterval.WaitAsync().ConfigureAwait(); - // } - //} - - //public override void Wait(CancellationToken cancellationToken = default) - //{ - // if (_isStreaming) - // { - // // We would have to read from the stream to get the run ID to poll for. - // throw new NotSupportedException("Cannot poll for status updates from streaming operation."); - // } - - // // See: https://platform.openai.com/docs/assistants/how-it-works/polling-for-updates - - // IEnumerator enumerator = GetUpdateResultEnumerator(); - - // while (enumerator.MoveNext()) - // { - // ApplyUpdate(enumerator.Current); - - // // Don't keep polling if would do so infinitely. - // if (_status == "requires_action") - // { - // return; - // } - - // cancellationToken.ThrowIfCancellationRequested(); - - // _pollingInterval.Wait(); - // } - //} - - //private void ApplyUpdate(ClientResult result) - //{ - // PipelineResponse response = result.GetRawResponse(); - - // using JsonDocument doc = JsonDocument.Parse(response.Content); - // _status = doc.RootElement.GetProperty("status"u8).GetString(); - - // IsCompleted = GetIsCompleted(_status!); - // SetRawResponse(response); - //} - - private static bool GetIsCompleted(string status) - { - bool hasCompleted = - status == "expired" || - status == "completed" || - status == "failed" || - status == "incomplete" || - status == "cancelled"; - - return hasCompleted; - } - - #endregion - - #region Generated protocol methods - i.e. TypeSpec "linked operations" - - /// - /// [Protocol Method] Retrieves a run. - /// - /// The ID of the [thread](/docs/api-reference/threads) that was run. - /// The ID of the run to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task GetRunAsync(string threadId, string runId, RequestOptions? options) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - - using PipelineMessage message = CreateGetRunRequest(threadId, runId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Retrieves a run. - /// - /// The ID of the [thread](/docs/api-reference/threads) that was run. - /// The ID of the run to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult GetRun(string threadId, string runId, RequestOptions? options) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - - using PipelineMessage message = CreateGetRunRequest(threadId, runId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - /// - /// [Protocol Method] Modifies a run. - /// - /// The ID of the [thread](/docs/api-reference/threads) that was run. - /// The ID of the run to modify. - /// The content to send as the body of the request. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// , or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task ModifyRunAsync(string threadId, string runId, BinaryContent content, RequestOptions? options = null) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - Argument.AssertNotNull(content, nameof(content)); - - using PipelineMessage message = CreateModifyRunRequest(threadId, runId, content, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Modifies a run. - /// - /// The ID of the [thread](/docs/api-reference/threads) that was run. - /// The ID of the run to modify. - /// The content to send as the body of the request. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// , or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult ModifyRun(string threadId, string runId, BinaryContent content, RequestOptions? options = null) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - Argument.AssertNotNull(content, nameof(content)); - - using PipelineMessage message = CreateModifyRunRequest(threadId, runId, content, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - /// - /// [Protocol Method] Cancels a run that is `in_progress`. - /// - /// The ID of the thread to which this run belongs. - /// The ID of the run to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task CancelRunAsync(string threadId, string runId, RequestOptions? options) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - - using PipelineMessage message = CreateCancelRunRequest(threadId, runId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Cancels a run that is `in_progress`. - /// - /// The ID of the thread to which this run belongs. - /// The ID of the run to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult CancelRun(string threadId, string runId, RequestOptions? options) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - - using PipelineMessage message = CreateCancelRunRequest(threadId, runId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - /// - /// [Protocol Method] When a run has the `status: "requires_action"` and `required_action.type` is - /// `submit_tool_outputs`, this endpoint can be used to submit the outputs from the tool calls once - /// they're all completed. All outputs must be submitted in a single request. - /// - /// The ID of the [thread](/docs/api-reference/threads) to which this run belongs. - /// The ID of the run that requires the tool output submission. - /// The content to send as the body of the request. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// , or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task SubmitToolOutputsToRunAsync(string threadId, string runId, BinaryContent content, RequestOptions? options = null) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - Argument.AssertNotNull(content, nameof(content)); - - PipelineMessage? message = null; - try - { - message = CreateSubmitToolOutputsToRunRequest(threadId, runId, content, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - finally - { - if (options?.BufferResponse != false) - { - message?.Dispose(); - } - } - } - - /// - /// [Protocol Method] When a run has the `status: "requires_action"` and `required_action.type` is - /// `submit_tool_outputs`, this endpoint can be used to submit the outputs from the tool calls once - /// they're all completed. All outputs must be submitted in a single request. - /// - /// The ID of the [thread](/docs/api-reference/threads) to which this run belongs. - /// The ID of the run that requires the tool output submission. - /// The content to send as the body of the request. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// , or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult SubmitToolOutputsToRun(string threadId, string runId, BinaryContent content, RequestOptions? options = null) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - Argument.AssertNotNull(content, nameof(content)); - - PipelineMessage? message = null; - try - { - message = CreateSubmitToolOutputsToRunRequest(threadId, runId, content, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - finally - { - if (options?.BufferResponse != false) - { - message?.Dispose(); - } - } - } - - /// - /// [Protocol Method] Returns a paginated collection of run steps belonging to a run. - /// - /// The ID of the thread the run and run steps belong to. - /// The ID of the run the run steps belong to. - /// - /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the - /// default is 20. - /// - /// - /// Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and`desc` - /// for descending order. Allowed values: "asc" | "desc" - /// - /// - /// A cursor for use in pagination. `after` is an object ID that defines your place in the list. - /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - /// subsequent call can include after=obj_foo in order to fetch the next page of the list. - /// - /// - /// A cursor for use in pagination. `before` is an object ID that defines your place in the list. - /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - /// subsequent call can include before=obj_foo in order to fetch the previous page of the list. - /// - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// A collection of service responses, each holding a page of values. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual IAsyncEnumerable GetRunStepsAsync(string threadId, string runId, int? limit, string order, string after, string before, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - - RunStepsPageEnumerator enumerator = new RunStepsPageEnumerator(_pipeline, _endpoint, threadId, runId, limit, order, after, before, options); - return PageCollectionHelpers.CreateAsync(enumerator); - } - - /// - /// [Protocol Method] Returns a paginated collection of run steps belonging to a run. - /// - /// The ID of the thread the run and run steps belong to. - /// The ID of the run the run steps belong to. - /// - /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the - /// default is 20. - /// - /// - /// Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and`desc` - /// for descending order. Allowed values: "asc" | "desc" - /// - /// - /// A cursor for use in pagination. `after` is an object ID that defines your place in the list. - /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - /// subsequent call can include after=obj_foo in order to fetch the next page of the list. - /// - /// - /// A cursor for use in pagination. `before` is an object ID that defines your place in the list. - /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - /// subsequent call can include before=obj_foo in order to fetch the previous page of the list. - /// - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// A collection of service responses, each holding a page of values. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual IEnumerable GetRunSteps(string threadId, string runId, int? limit, string order, string after, string before, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - - RunStepsPageEnumerator enumerator = new RunStepsPageEnumerator(_pipeline, _endpoint, threadId, runId, limit, order, after, before, options); - return PageCollectionHelpers.Create(enumerator); - } - - /// - /// [Protocol Method] Retrieves a run step. - /// - /// The ID of the thread to which the run and run step belongs. - /// The ID of the run to which the run step belongs. - /// The ID of the run step to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// , or is null. - /// , or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task GetRunStepAsync(string threadId, string runId, string stepId, RequestOptions? options) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - Argument.AssertNotNullOrEmpty(stepId, nameof(stepId)); - - using PipelineMessage message = CreateGetRunStepRequest(threadId, runId, stepId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Retrieves a run step. - /// - /// The ID of the thread to which the run and run step belongs. - /// The ID of the run to which the run step belongs. - /// The ID of the run step to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// , or is null. - /// , or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult GetRunStep(string threadId, string runId, string stepId, RequestOptions? options) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - Argument.AssertNotNullOrEmpty(stepId, nameof(stepId)); - - using PipelineMessage message = CreateGetRunStepRequest(threadId, runId, stepId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - internal PipelineMessage CreateCreateRunRequest(string threadId, BinaryContent content, RequestOptions? options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "POST"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/threads/", false); - uri.AppendPath(threadId, true); - uri.AppendPath("/runs", false); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - request.Headers.Set("Content-Type", "application/json"); - request.Content = content; - message.Apply(options); - return message; - } - - internal PipelineMessage CreateGetRunRequest(string threadId, string runId, RequestOptions? options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/threads/", false); - uri.AppendPath(threadId, true); - uri.AppendPath("/runs/", false); - uri.AppendPath(runId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateModifyRunRequest(string threadId, string runId, BinaryContent content, RequestOptions? options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "POST"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/threads/", false); - uri.AppendPath(threadId, true); - uri.AppendPath("/runs/", false); - uri.AppendPath(runId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - request.Headers.Set("Content-Type", "application/json"); - request.Content = content; - message.Apply(options); - return message; - } - - internal PipelineMessage CreateCancelRunRequest(string threadId, string runId, RequestOptions? options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "POST"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/threads/", false); - uri.AppendPath(threadId, true); - uri.AppendPath("/runs/", false); - uri.AppendPath(runId, true); - uri.AppendPath("/cancel", false); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateSubmitToolOutputsToRunRequest(string threadId, string runId, BinaryContent content, RequestOptions? options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "POST"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/threads/", false); - uri.AppendPath(threadId, true); - uri.AppendPath("/runs/", false); - uri.AppendPath(runId, true); - uri.AppendPath("/submit_tool_outputs", false); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - request.Headers.Set("Content-Type", "application/json"); - request.Content = content; - message.Apply(options); - return message; - } - - internal PipelineMessage CreateGetRunStepsRequest(string threadId, string runId, int? limit, string order, string after, string before, RequestOptions? options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/threads/", false); - uri.AppendPath(threadId, true); - uri.AppendPath("/runs/", false); - uri.AppendPath(runId, true); - uri.AppendPath("/steps", false); - if (limit != null) - { - uri.AppendQuery("limit", limit.Value, true); - } - if (order != null) - { - uri.AppendQuery("order", order, true); - } - if (after != null) - { - uri.AppendQuery("after", after, true); - } - if (before != null) - { - uri.AppendQuery("before", before, true); - } - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateGetRunStepRequest(string threadId, string runId, string stepId, RequestOptions? options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/threads/", false); - uri.AppendPath(threadId, true); - uri.AppendPath("/runs/", false); - uri.AppendPath(runId, true); - uri.AppendPath("/steps/", false); - uri.AppendPath(stepId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - private static PipelineMessageClassifier? _pipelineMessageClassifier200; - private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); - #endregion -} \ No newline at end of file diff --git a/src/To.Be.Generated/RunOperation.cs b/src/To.Be.Generated/RunOperation.cs deleted file mode 100644 index e2c53430..00000000 --- a/src/To.Be.Generated/RunOperation.cs +++ /dev/null @@ -1,392 +0,0 @@ -using System; -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Collections.Generic; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; - -#nullable enable - -namespace OpenAI.Assistants; - -// Convenience version -public partial class RunOperation : ClientResult -{ - // For use with polling convenience methods where the response has been - // obtained prior to creation of the LRO type. - internal RunOperation( - ClientPipeline pipeline, - Uri endpoint, - ThreadRun value, - RunStatus status, - PipelineResponse response) - : base(response) - { - _pipeline = pipeline; - _endpoint = endpoint; - _pollingInterval = new(); - - if (response.Headers.TryGetValue("Content-Type", out string? contentType) && - contentType == "text/event-stream; charset=utf-8") - { - throw new ArgumentException("Cannot create polling operation from streaming response.", nameof(response)); - } - - Value = value; - Status = status; - - ThreadId = value.ThreadId; - RunId = value.Id; - - RehydrationToken = new RunOperationToken(value.ThreadId, value.Id); - } - - // For use with streaming convenience methods - response hasn't been provided yet. - internal RunOperation( - ClientPipeline pipeline, - Uri endpoint) - : base() - { - _pipeline = pipeline; - _endpoint = endpoint; - - // This constructor is provided for streaming convenience method only. - // Because of this, we don't set the polling interval type. - } - - // Note: these all have to be nullable because the derived streaming type - // cannot set them until it reads the first event from the SSE stream. - public string? RunId { get => _runId; protected set => _runId = value; } - public string? ThreadId { get => _threadId; protected set => _threadId = value; } - - public ThreadRun? Value { get; protected set; } - public RunStatus? Status { get; protected set; } - - #region OperationResult methods - - public virtual async Task WaitUntilStoppedAsync(CancellationToken cancellationToken = default) - => await WaitUntilStoppedAsync(default, cancellationToken).ConfigureAwait(false); - - public virtual void WaitUntilStopped(CancellationToken cancellationToken = default) - => WaitUntilStopped(default, cancellationToken); - - public virtual async Task WaitUntilStoppedAsync(TimeSpan? pollingInterval, CancellationToken cancellationToken = default) - { - if (IsStreaming) - { - // We would have to read from the stream to get the run ID to poll for. - throw new NotSupportedException("Cannot poll for status updates from streaming operation."); - } - - await foreach (ThreadRun update in GetUpdatesAsync(pollingInterval, cancellationToken)) - { - // Don't keep polling if would do so infinitely. - if (update.Status == RunStatus.RequiresAction) - { - return; - } - } - } - - public virtual void WaitUntilStopped(TimeSpan? pollingInterval, CancellationToken cancellationToken = default) - { - if (IsStreaming) - { - // We would have to read from the stream to get the run ID to poll for. - throw new NotSupportedException("Cannot poll for status updates from streaming operation."); - } - - foreach (ThreadRun update in GetUpdates(pollingInterval, cancellationToken)) - { - // Don't keep polling if would do so infinitely. - if (update.Status == RunStatus.RequiresAction) - { - return; - } - } - } - - // Expose enumerable APIs similar to the streaming ones. - public virtual async IAsyncEnumerable GetUpdatesAsync( - TimeSpan? pollingInterval = default, - [EnumeratorCancellation] CancellationToken cancellationToken = default) - { - if (pollingInterval is not null) - { - // TODO: don't allocate - _pollingInterval = new PollingInterval(pollingInterval); - } - - IAsyncEnumerator> enumerator = - new RunOperationUpdateEnumerator(_pipeline, _endpoint, _threadId!, _runId!, cancellationToken); - - while (await enumerator.MoveNextAsync().ConfigureAwait(false)) - { - ApplyUpdate(enumerator.Current); - - yield return enumerator.Current; - - // TODO: do we need null check? - await _pollingInterval!.WaitAsync(cancellationToken).ConfigureAwait(false); - } - } - - public virtual IEnumerable GetUpdates( - TimeSpan? pollingInterval = default, - CancellationToken cancellationToken = default) - { - if (pollingInterval is not null) - { - // TODO: don't allocate - _pollingInterval = new PollingInterval(pollingInterval); - } - - IEnumerator> enumerator = new RunOperationUpdateEnumerator( - _pipeline, _endpoint, _threadId!, _runId!, cancellationToken); - - while (enumerator.MoveNext()) - { - ApplyUpdate(enumerator.Current); - - yield return enumerator.Current; - - // TODO: do we need null check? - _pollingInterval!.Wait(); - } - } - - private void ApplyUpdate(ClientResult update) - { - Value = update; - Status = update.Value.Status; - IsCompleted = Status.Value.IsTerminal; - - SetRawResponse(update.GetRawResponse()); - } - - #endregion - - #region Convenience overloads of generated protocol methods - - /// - /// Gets an existing from a known . - /// - /// A token that can be used to cancel this method call. - /// The existing instance. - public virtual async Task> GetRunAsync(CancellationToken cancellationToken = default) - { - ClientResult protocolResult = await GetRunAsync(_threadId!, _runId!, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - return CreateResultFromProtocol(protocolResult, ThreadRun.FromResponse); - } - - /// - /// Gets an existing from a known . - /// - /// A token that can be used to cancel this method call. - /// The existing instance. - public virtual ClientResult GetRun(CancellationToken cancellationToken = default) - { - ClientResult protocolResult = GetRun(_threadId!, _runId!, cancellationToken.ToRequestOptions()); - return CreateResultFromProtocol(protocolResult, ThreadRun.FromResponse); - } - - /// - /// Cancels an in-progress . - /// - /// A token that can be used to cancel this method call. - /// An updated instance, reflecting the new status of the run. - public virtual async Task> CancelRunAsync(CancellationToken cancellationToken = default) - { - ClientResult protocolResult = await CancelRunAsync(_threadId!, _runId!, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - return CreateResultFromProtocol(protocolResult, ThreadRun.FromResponse); - } - - /// - /// Cancels an in-progress . - /// - /// A token that can be used to cancel this method call. - /// An updated instance, reflecting the new status of the run. - public virtual ClientResult CancelRun(CancellationToken cancellationToken = default) - { - ClientResult protocolResult = CancelRun(_threadId!, _runId!, cancellationToken.ToRequestOptions()); - return CreateResultFromProtocol(protocolResult, ThreadRun.FromResponse); - } - - /// - /// Submits a collection of required tool call outputs to a run and resumes the run. - /// - /// - /// The tool outputs, corresponding to instances from the run. - /// - /// A token that can be used to cancel this method call. - /// The , updated after the submission was processed. - public virtual async Task SubmitToolOutputsToRunAsync( - IEnumerable toolOutputs, - CancellationToken cancellationToken = default) - { - BinaryContent content = new InternalSubmitToolOutputsRunRequest(toolOutputs).ToBinaryContent(); - ClientResult protocolResult = await SubmitToolOutputsToRunAsync(_threadId!, _runId!, content, cancellationToken.ToRequestOptions()) - .ConfigureAwait(false); - ClientResult update = CreateResultFromProtocol(protocolResult, ThreadRun.FromResponse); - ApplyUpdate(update); - } - - /// - /// Submits a collection of required tool call outputs to a run and resumes the run. - /// - /// - /// The tool outputs, corresponding to instances from the run. - /// - /// A token that can be used to cancel this method call. - /// The , updated after the submission was processed. - public virtual void SubmitToolOutputsToRun( - IEnumerable toolOutputs, - CancellationToken cancellationToken = default) - { - BinaryContent content = new InternalSubmitToolOutputsRunRequest(toolOutputs).ToBinaryContent(); - ClientResult protocolResult = SubmitToolOutputsToRun(_threadId!, _runId!, content, cancellationToken.ToRequestOptions()); - ClientResult update = CreateResultFromProtocol(protocolResult, ThreadRun.FromResponse); - ApplyUpdate(update); - } - - /// - /// Gets a page collection holding instances associated with a . - /// - /// - /// A token that can be used to cancel this method call. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual AsyncPageCollection GetRunStepsAsync( - RunStepCollectionOptions? options = default, - CancellationToken cancellationToken = default) - { - RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, - _threadId!, - _runId!, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); - } - - /// - /// Rehydrates a page collection holding instances from a page token. - /// - /// Page token corresponding to the first page of the collection to rehydrate. - /// A token that can be used to cancel this method call. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual AsyncPageCollection GetRunStepsAsync( - ContinuationToken firstPageToken, - CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); - - RunStepsPageToken pageToken = RunStepsPageToken.FromToken(firstPageToken); - RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.ThreadId, - pageToken.RunId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); - } - - /// - /// Gets a page collection holding instances associated with a . - /// - /// - /// A token that can be used to cancel this method call. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual PageCollection GetRunSteps( - RunStepCollectionOptions? options = default, - CancellationToken cancellationToken = default) - { - RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, - ThreadId!, - RunId!, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); - } - - /// - /// Rehydrates a page collection holding instances from a page token. - /// - /// Page token corresponding to the first page of the collection to rehydrate. - /// A token that can be used to cancel this method call. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual PageCollection GetRunSteps( - ContinuationToken firstPageToken, - CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); - - RunStepsPageToken pageToken = RunStepsPageToken.FromToken(firstPageToken); - RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.ThreadId, - pageToken.RunId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); - } - - /// - /// Gets a single run step from a run. - /// - /// The ID of the run step. - /// A token that can be used to cancel this method call. - /// A instance corresponding to the specified step. - public virtual async Task> GetRunStepAsync(string stepId, CancellationToken cancellationToken = default) - { - ClientResult protocolResult = await GetRunStepAsync(_threadId!, _runId!, stepId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - return CreateResultFromProtocol(protocolResult, RunStep.FromResponse); - } - - /// - /// Gets a single run step from a run. - /// - /// The ID of the run step. - /// A token that can be used to cancel this method call. - /// A instance corresponding to the specified step. - public virtual ClientResult GetRunStep(string stepId, CancellationToken cancellationToken = default) - { - ClientResult protocolResult = GetRunStep(_threadId!, _runId!, stepId, cancellationToken.ToRequestOptions()); - return CreateResultFromProtocol(protocolResult, RunStep.FromResponse); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ClientResult CreateResultFromProtocol(ClientResult protocolResult, Func responseDeserializer) - { - PipelineResponse pipelineResponse = protocolResult.GetRawResponse(); - T deserializedResultValue = responseDeserializer.Invoke(pipelineResponse); - return ClientResult.FromValue(deserializedResultValue, pipelineResponse); - } - - #endregion -} \ No newline at end of file diff --git a/src/To.Be.Generated/RunOperationToken.cs b/src/To.Be.Generated/RunOperationToken.cs deleted file mode 100644 index b57dec15..00000000 --- a/src/To.Be.Generated/RunOperationToken.cs +++ /dev/null @@ -1,102 +0,0 @@ -using System; -using System.ClientModel; -using System.Diagnostics; -using System.IO; -using System.Text.Json; - -#nullable enable - -namespace OpenAI.Assistants; - -internal class RunOperationToken : ContinuationToken -{ - public RunOperationToken(string threadId, string runId) - { - ThreadId = threadId; - RunId = runId; - } - - public string ThreadId { get; } - - public string RunId { get; } - - public override BinaryData ToBytes() - { - using MemoryStream stream = new(); - using Utf8JsonWriter writer = new(stream); - - writer.WriteStartObject(); - - writer.WriteString("threadId", ThreadId); - writer.WriteString("runId", RunId); - - writer.WriteEndObject(); - - writer.Flush(); - stream.Position = 0; - - return BinaryData.FromStream(stream); - } - - public static RunOperationToken FromToken(ContinuationToken continuationToken) - { - if (continuationToken is RunOperationToken token) - { - return token; - } - - BinaryData data = continuationToken.ToBytes(); - - if (data.ToMemory().Length == 0) - { - throw new ArgumentException("Failed to create RunOperationToken from provided continuationToken.", nameof(continuationToken)); - } - - Utf8JsonReader reader = new(data); - - string threadId = null!; - string runId = null!; - - reader.Read(); - - Debug.Assert(reader.TokenType == JsonTokenType.StartObject); - - while (reader.Read()) - { - if (reader.TokenType == JsonTokenType.EndObject) - { - break; - } - - Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); - - string propertyName = reader.GetString()!; - - switch (propertyName) - { - case "threadId": - reader.Read(); - Debug.Assert(reader.TokenType == JsonTokenType.String); - threadId = reader.GetString()!; - break; - - case "runId": - reader.Read(); - Debug.Assert(reader.TokenType == JsonTokenType.String); - threadId = reader.GetString()!; - break; - - default: - throw new JsonException($"Unrecognized property '{propertyName}'."); - } - } - - if (threadId is null || runId is null) - { - throw new ArgumentException("Failed to create RunOperationToken from provided continuationToken.", nameof(continuationToken)); - } - - return new(threadId, runId); - } -} - diff --git a/src/To.Be.Generated/RunOperationUpdateEnumerator.Protocol.cs b/src/To.Be.Generated/RunOperationUpdateEnumerator.Protocol.cs deleted file mode 100644 index 3185d0b0..00000000 --- a/src/To.Be.Generated/RunOperationUpdateEnumerator.Protocol.cs +++ /dev/null @@ -1,175 +0,0 @@ -using System; -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Collections; -using System.Collections.Generic; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -#nullable enable - -namespace OpenAI.Assistants; - -internal partial class RunOperationUpdateEnumerator : - IAsyncEnumerator, - IEnumerator -{ - private readonly ClientPipeline _pipeline; - private readonly Uri _endpoint; - private readonly string _threadId; - private readonly string _runId; - private readonly CancellationToken _cancellationToken; - - private ClientResult? _current; - private bool _hasNext = true; - - public RunOperationUpdateEnumerator( - ClientPipeline pipeline, - Uri endpoint, - string threadId, - string runId, - CancellationToken cancellationToken) - { - _pipeline = pipeline; - _endpoint = endpoint; - - _threadId = threadId; - _runId = runId; - - _cancellationToken = cancellationToken; - } - - public ClientResult Current => _current!; - - #region IEnumerator methods - - object IEnumerator.Current => _current!; - - bool IEnumerator.MoveNext() - { - if (!_hasNext) - { - _current = null; - return false; - } - - ClientResult result = GetRun(_threadId, _runId, _cancellationToken.ToRequestOptions()); - - _current = result; - _hasNext = HasNext(result); - - return true; - } - - void IEnumerator.Reset() => _current = null; - - void IDisposable.Dispose() { } - - #endregion - - #region IAsyncEnumerator methods - - ClientResult IAsyncEnumerator.Current => _current!; - - public async ValueTask MoveNextAsync() - { - if (!_hasNext) - { - _current = null; - return false; - } - - ClientResult result = await GetRunAsync(_threadId, _runId, _cancellationToken.ToRequestOptions()).ConfigureAwait(false); - - _current = result; - _hasNext = HasNext(result); - - return true; - } - - // TODO: handle Dispose and DisposeAsync using proper patterns? - ValueTask IAsyncDisposable.DisposeAsync() => default; - - #endregion - - // Methods used by both implementations - - private bool HasNext(ClientResult result) - { - PipelineResponse response = result.GetRawResponse(); - - // TODO: don't parse JsonDocument twice if possible - using JsonDocument doc = JsonDocument.Parse(response.Content); - string? status = doc.RootElement.GetProperty("status"u8).GetString(); - - bool isComplete = status == "expired" || - status == "completed" || - status == "failed" || - status == "incomplete" || - status == "cancelled"; - - return !isComplete; - } - - // Generated methods - - /// - /// [Protocol Method] Retrieves a run. - /// - /// The ID of the [thread](/docs/api-reference/threads) that was run. - /// The ID of the run to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task GetRunAsync(string threadId, string runId, RequestOptions? options) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - - using PipelineMessage message = CreateGetRunRequest(threadId, runId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Retrieves a run. - /// - /// The ID of the [thread](/docs/api-reference/threads) that was run. - /// The ID of the run to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult GetRun(string threadId, string runId, RequestOptions? options) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - - using PipelineMessage message = CreateGetRunRequest(threadId, runId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - internal PipelineMessage CreateGetRunRequest(string threadId, string runId, RequestOptions? options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/threads/", false); - uri.AppendPath(threadId, true); - uri.AppendPath("/runs/", false); - uri.AppendPath(runId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - private static PipelineMessageClassifier? _pipelineMessageClassifier200; - private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); -} diff --git a/src/To.Be.Generated/RunOperationUpdateEnumerator.cs b/src/To.Be.Generated/RunOperationUpdateEnumerator.cs deleted file mode 100644 index 8d485771..00000000 --- a/src/To.Be.Generated/RunOperationUpdateEnumerator.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Collections.Generic; - -#nullable enable - -namespace OpenAI.Assistants; - -internal partial class RunOperationUpdateEnumerator : - IAsyncEnumerator>, - IEnumerator> -{ - #region IEnumerator> methods - - ClientResult IEnumerator>.Current - { - get - { - if (Current is null) - { - return default!; - } - - return GetUpdateFromResult(Current); - } - } - - #endregion - - #region IAsyncEnumerator> methods - - ClientResult IAsyncEnumerator>.Current - { - get - { - if (Current is null) - { - return default!; - } - - return GetUpdateFromResult(Current); - } - } - - #endregion - - // Methods used by convenience implementation - private ClientResult GetUpdateFromResult(ClientResult result) - { - PipelineResponse response = result.GetRawResponse(); - ThreadRun run = ThreadRun.FromResponse(response); - return ClientResult.FromValue(run, response); - } -} diff --git a/src/To.Be.Generated/StreamingRunOperation.cs b/src/To.Be.Generated/StreamingRunOperation.cs deleted file mode 100644 index d47542fe..00000000 --- a/src/To.Be.Generated/StreamingRunOperation.cs +++ /dev/null @@ -1,280 +0,0 @@ -using System; -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; - -#nullable enable - -namespace OpenAI.Assistants; - -// Streaming version -public partial class StreamingRunOperation : RunOperation -{ - private readonly Func> _createRunAsync; - private readonly Func _createRun; - - - private StreamingRunOperationUpdateEnumerator? _enumerator; - - internal StreamingRunOperation( - ClientPipeline pipeline, - Uri endpoint, - - // Note if we pass funcs we don't need to pass in the pipeline. - Func> createRunAsync, - Func createRun) - : base(pipeline, endpoint) - { - _createRunAsync = createRunAsync; - _createRun = createRun; - } - - // TODO: this duplicates a field on the base type. Address? - public override bool IsCompleted { get; protected set; } - - public override async Task WaitUntilStoppedAsync(CancellationToken cancellationToken = default) - { - // TODO: add validation that stream is only requested and enumerated once. - // TODO: Make sure you can't create the same run twice and/or submit tools twice - // somehow, even accidentally. - - await foreach (StreamingUpdate update in GetUpdatesStreamingAsync(cancellationToken).ConfigureAwait(false)) - { - // Should terminate naturally when get to "requires action" because - // the SSE stream will end. - } - } - - public override void WaitUntilStopped(CancellationToken cancellationToken = default) - { - foreach (StreamingUpdate update in GetUpdatesStreaming(cancellationToken)) - { - // Should terminate naturally when get to "requires action" because - // the SSE stream will end. - } - } - - // Public APIs specific to streaming LRO - public virtual async IAsyncEnumerable GetUpdatesStreamingAsync( - [EnumeratorCancellation] CancellationToken cancellationToken = default) - { - try - { - if (_enumerator is null) - { - AsyncStreamingUpdateCollection updates = new AsyncStreamingUpdateCollection(_createRunAsync); - _enumerator = new StreamingRunOperationUpdateEnumerator(updates); - } - - while (await _enumerator.MoveNextAsync().ConfigureAwait(false)) - { - if (_enumerator.Current is RunUpdate update) - { - ApplyUpdate(update); - } - - cancellationToken.ThrowIfCancellationRequested(); - - yield return _enumerator.Current; - } - } - finally - { - if (_enumerator != null) - { - await _enumerator.DisposeAsync(); - _enumerator = null; - } - } - } - - public virtual IEnumerable GetUpdatesStreaming(CancellationToken cancellationToken = default) - { - try - { - if (_enumerator is null) - { - StreamingUpdateCollection updates = new StreamingUpdateCollection(_createRun); - _enumerator = new StreamingRunOperationUpdateEnumerator(updates); - } - - while (_enumerator.MoveNext()) - { - if (_enumerator.Current is RunUpdate update) - { - ApplyUpdate(update); - } - - cancellationToken.ThrowIfCancellationRequested(); - - yield return _enumerator.Current; - } - } - finally - { - if (_enumerator != null) - { - _enumerator.Dispose(); - _enumerator = null; - } - } - } - - public override async IAsyncEnumerable GetUpdatesAsync(TimeSpan? pollingInterval = null, [EnumeratorCancellation] CancellationToken cancellationToken = default) - { - if (pollingInterval is not null) - { - throw new NotSupportedException("Cannot specify polling interval for streaming operation."); - } - - await foreach (StreamingUpdate update in GetUpdatesStreamingAsync(cancellationToken).ConfigureAwait(false)) - { - if (update is RunUpdate runUpdate) - { - yield return runUpdate; - } - } - } - - public override IEnumerable GetUpdates(TimeSpan? pollingInterval = null, CancellationToken cancellationToken = default) - { - if (pollingInterval is not null) - { - throw new NotSupportedException("Cannot specify polling interval for streaming operation."); - } - - foreach (StreamingUpdate update in GetUpdatesStreaming()) - { - if (update is RunUpdate runUpdate) - { - yield return runUpdate; - } - } - } - - private void ApplyUpdate(ThreadRun update) - { - RunId ??= update.Id; - ThreadId ??= update.ThreadId; - - Value = update; - Status = update.Status; - IsCompleted = update.Status.IsTerminal; - - SetRawResponse(_enumerator!.GetRawResponse()); - } - - public virtual async Task SubmitToolOutputsToRunStreamingAsync( - IEnumerable toolOutputs, - CancellationToken cancellationToken = default) - { - if (ThreadId is null || RunId is null) - { - throw new InvalidOperationException("Cannot submit tools until first update stream has been applied."); - } - - BinaryContent content = new InternalSubmitToolOutputsRunRequest( - toolOutputs.ToList(), stream: true, null).ToBinaryContent(); - - // TODO: can we do this the same way as this in the other method instead - // of having to take all those funcs? - async Task getResultAsync() => - await SubmitToolOutputsToRunAsync(ThreadId, RunId, content, cancellationToken.ToRequestOptions(streaming: true)) - .ConfigureAwait(false); - - AsyncStreamingUpdateCollection updates = new AsyncStreamingUpdateCollection(getResultAsync); - if (_enumerator is null) - { - _enumerator = new StreamingRunOperationUpdateEnumerator(updates); - } - else - { - await _enumerator.ReplaceUpdateCollectionAsync(updates).ConfigureAwait(false); - } - } - - public virtual void SubmitToolOutputsToRunStreaming( - IEnumerable toolOutputs, - CancellationToken cancellationToken = default) - { - if (ThreadId is null || RunId is null) - { - throw new InvalidOperationException("Cannot submit tools until first update stream has been applied."); - } - - if (_enumerator is null) - { - throw new InvalidOperationException( - "Cannot submit tools until first run update stream has been enumerated. " + - "Call 'Wait' or 'GetUpdatesStreaming' to read update stream."); - } - - BinaryContent content = new InternalSubmitToolOutputsRunRequest( - toolOutputs.ToList(), stream: true, null).ToBinaryContent(); - - // TODO: can we do this the same way as this in the other method instead - // of having to take all those funcs? - ClientResult getResult() => - SubmitToolOutputsToRun(ThreadId, RunId, content, cancellationToken.ToRequestOptions(streaming: true)); - - StreamingUpdateCollection updates = new StreamingUpdateCollection(getResult); - if (_enumerator is null) - { - _enumerator = new StreamingRunOperationUpdateEnumerator(updates); - } - else - { - _enumerator.ReplaceUpdateCollection(updates); - } - } - - #region hide - - //// used to defer first request. - //internal virtual async Task CreateRunAsync(string threadId, BinaryContent content, RequestOptions? options = null) - //{ - // Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - // Argument.AssertNotNull(content, nameof(content)); - - // PipelineMessage? message = null; - // try - // { - // message = CreateCreateRunRequest(threadId, content, options); - // return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - // } - // finally - // { - // if (options?.BufferResponse != false) - // { - // message?.Dispose(); - // } - // } - //} - - //internal PipelineMessage CreateCreateRunRequest(string threadId, BinaryContent content, RequestOptions? options) - //{ - // var message = Pipeline.CreateMessage(); - // message.ResponseClassifier = PipelineMessageClassifier200; - // var request = message.Request; - // request.Method = "POST"; - // var uri = new ClientUriBuilder(); - // uri.Reset(_endpoint); - // uri.AppendPath("/threads/", false); - // uri.AppendPath(threadId, true); - // uri.AppendPath("/runs", false); - // request.Uri = uri.ToUri(); - // request.Headers.Set("Accept", "application/json"); - // request.Headers.Set("Content-Type", "application/json"); - // request.Content = content; - // message.Apply(options); - // return message; - //} - - //private static PipelineMessageClassifier? _pipelineMessageClassifier200; - //private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); - #endregion -} diff --git a/src/To.Be.Generated/StreamingRunOperationUpdateEnumerator.cs b/src/To.Be.Generated/StreamingRunOperationUpdateEnumerator.cs deleted file mode 100644 index 93a933cb..00000000 --- a/src/To.Be.Generated/StreamingRunOperationUpdateEnumerator.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.ClientModel.Primitives; -using System.Collections; -using System.Collections.Generic; -using System.Threading.Tasks; - -#nullable enable - -namespace OpenAI.Assistants; - -internal partial class StreamingRunOperationUpdateEnumerator : - IAsyncEnumerator, - IEnumerator -{ - private StreamingUpdate? _current; - - private AsyncStreamingUpdateCollection? _asyncUpdates; - private IAsyncEnumerator? _asyncEnumerator; - - private StreamingUpdateCollection? _updates; - private IEnumerator? _enumerator; - - public StreamingRunOperationUpdateEnumerator( - AsyncStreamingUpdateCollection updates) - { - _asyncUpdates = updates; - } - - public StreamingRunOperationUpdateEnumerator( - StreamingUpdateCollection updates) - { - _updates = updates; - } - - // Cache this here for now - public PipelineResponse GetRawResponse() => - _asyncUpdates?.GetRawResponse() ?? - _updates?.GetRawResponse() ?? - throw new InvalidOperationException("No response available."); - - public StreamingUpdate Current => _current!; - - #region IEnumerator methods - - object IEnumerator.Current => _current!; - - public bool MoveNext() - { - if (_updates is null) - { - throw new InvalidOperationException("Cannot MoveNext after starting enumerator asynchronously."); - } - - _enumerator ??= _updates.GetEnumerator(); - - bool movedNext = _enumerator.MoveNext(); - _current = _enumerator.Current; - return movedNext; - } - - void IEnumerator.Reset() - { - throw new NotSupportedException("Cannot reset streaming enumerator."); - } - - public void Dispose() - { - if (_enumerator != null) - { - _enumerator.Dispose(); - _enumerator = null; - } - } - - #endregion - - #region IAsyncEnumerator methods - - public async ValueTask MoveNextAsync() - { - if (_asyncUpdates is null) - { - throw new InvalidOperationException("Cannot MoveNextAsync after starting enumerator synchronously."); - } - - _asyncEnumerator ??= _asyncUpdates.GetAsyncEnumerator(); - - bool movedNext = await _asyncEnumerator.MoveNextAsync().ConfigureAwait(false); - _current = _asyncEnumerator.Current; - return movedNext; - } - - public async ValueTask DisposeAsync() - { - // TODO: implement according to pattern - - if (_asyncEnumerator is null) - { - return; - } - - await _asyncEnumerator.DisposeAsync().ConfigureAwait(false); - } - - #endregion - - public async Task ReplaceUpdateCollectionAsync(AsyncStreamingUpdateCollection updates) - { - if (_asyncUpdates is null) - { - throw new InvalidOperationException("Cannot replace null update collection."); - } - - if (_updates is not null || _enumerator is not null) - { - throw new InvalidOperationException("Cannot being enumerating asynchronously after enumerating synchronously."); - } - - if (_asyncEnumerator is not null) - { - await _asyncEnumerator.DisposeAsync().ConfigureAwait(false); - _asyncEnumerator = null; - } - - _asyncUpdates = updates; - } - - public void ReplaceUpdateCollection(StreamingUpdateCollection updates) - { - if (_updates is null) - { - throw new InvalidOperationException("Cannot replace null update collection."); - } - - if (_asyncUpdates is not null || _asyncEnumerator is not null) - { - throw new InvalidOperationException("Cannot being enumerating synchronously after enumerating asynchronously."); - } - - _enumerator?.Dispose(); - _enumerator = null; - - _updates = updates; - } -} From 77a8abe1a2f396e93d9e7d8ef8295ce0e5eb104c Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Mon, 5 Aug 2024 16:54:27 -0700 Subject: [PATCH 03/14] misc tidy --- .../BatchOperation.Protocol.cs | 77 ++++++-- ...BatchOperationUpdateEnumerator.Protocol.cs | 165 ------------------ .../VectorStoreFileBatchOperation.Protocol.cs | 34 ---- 3 files changed, 60 insertions(+), 216 deletions(-) delete mode 100644 src/To.Be.Generated/BatchOperationUpdateEnumerator.Protocol.cs diff --git a/src/To.Be.Generated/BatchOperation.Protocol.cs b/src/To.Be.Generated/BatchOperation.Protocol.cs index bc0398d1..64504c91 100644 --- a/src/To.Be.Generated/BatchOperation.Protocol.cs +++ b/src/To.Be.Generated/BatchOperation.Protocol.cs @@ -1,7 +1,6 @@ using System; using System.ClientModel; using System.ClientModel.Primitives; -using System.Collections.Generic; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -15,7 +14,7 @@ public partial class BatchOperation : OperationResult { private readonly ClientPipeline _pipeline; private readonly Uri _endpoint; - + private readonly string _batchId; private PollingInterval _pollingInterval; @@ -32,7 +31,7 @@ internal BatchOperation( { _pipeline = pipeline; _endpoint = endpoint; - + _batchId = batchId; IsCompleted = GetIsCompleted(status); @@ -49,29 +48,25 @@ internal BatchOperation( // These are replaced when LRO is evolved to have conveniences public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) { - IAsyncEnumerator enumerator = - new BatchOperationUpdateEnumerator(_pipeline, _endpoint, _batchId, cancellationToken); - - while (await enumerator.MoveNextAsync().ConfigureAwait(false)) + while (!IsCompleted) { - ApplyUpdate(enumerator.Current); - await _pollingInterval.WaitAsync(cancellationToken); + + ClientResult result = await GetBatchAsync(_batchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + + ApplyUpdate(result); } } public override void WaitForCompletion(CancellationToken cancellationToken = default) { - IEnumerator enumerator = new BatchOperationUpdateEnumerator( - _pipeline, _endpoint, _batchId, cancellationToken); - - while (enumerator.MoveNext()) + while (!IsCompleted) { - ApplyUpdate(enumerator.Current); + _pollingInterval.Wait(); - cancellationToken.ThrowIfCancellationRequested(); + ClientResult result = GetBatch(_batchId, cancellationToken.ToRequestOptions()); - _pollingInterval.Wait(); + ApplyUpdate(result); } } @@ -96,6 +91,40 @@ private static bool GetIsCompleted(string? status) // Generated protocol methods + /// + /// [Protocol Method] Retrieves a batch. + /// + /// The ID of the batch to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetBatchAsync(string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateRetrieveBatchRequest(batchId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Retrieves a batch. + /// + /// The ID of the batch to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult GetBatch(string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateRetrieveBatchRequest(batchId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + /// /// [Protocol Method] Cancels an in-progress batch. /// @@ -129,6 +158,21 @@ public virtual ClientResult CancelBatch(string batchId, RequestOptions options) using PipelineMessage message = CreateCancelBatchRequest(batchId, options); return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } + internal PipelineMessage CreateRetrieveBatchRequest(string batchId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/batches/", false); + uri.AppendPath(batchId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } internal PipelineMessage CreateCancelBatchRequest(string batchId, RequestOptions options) { @@ -147,7 +191,6 @@ internal PipelineMessage CreateCancelBatchRequest(string batchId, RequestOptions return message; } - private static PipelineMessageClassifier? _pipelineMessageClassifier200; private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); } \ No newline at end of file diff --git a/src/To.Be.Generated/BatchOperationUpdateEnumerator.Protocol.cs b/src/To.Be.Generated/BatchOperationUpdateEnumerator.Protocol.cs deleted file mode 100644 index ae568011..00000000 --- a/src/To.Be.Generated/BatchOperationUpdateEnumerator.Protocol.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System; -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Collections; -using System.Collections.Generic; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -#nullable enable - -namespace OpenAI.Batch; - -internal partial class BatchOperationUpdateEnumerator : - IAsyncEnumerator, - IEnumerator -{ - private readonly ClientPipeline _pipeline; - private readonly Uri _endpoint; - private readonly CancellationToken _cancellationToken; - - private readonly string _batchId; - - // TODO: does this one need to be nullable? - private ClientResult? _current; - private bool _hasNext = true; - - public BatchOperationUpdateEnumerator( - ClientPipeline pipeline, - Uri endpoint, - string batchId, - CancellationToken cancellationToken) - { - _pipeline = pipeline; - _endpoint = endpoint; - - _batchId = batchId; - - _cancellationToken = cancellationToken; - } - - public ClientResult Current => _current!; - - #region IEnumerator methods - - object IEnumerator.Current => _current!; - - bool IEnumerator.MoveNext() - { - if (!_hasNext) - { - _current = null; - return false; - } - - ClientResult result = GetBatch(_batchId, _cancellationToken.ToRequestOptions()); - - _current = result; - _hasNext = HasNext(result); - - return true; - } - - void IEnumerator.Reset() => _current = null; - - void IDisposable.Dispose() { } - - #endregion - - #region IAsyncEnumerator methods - - ClientResult IAsyncEnumerator.Current => _current!; - - public async ValueTask MoveNextAsync() - { - if (!_hasNext) - { - _current = null; - return false; - } - - ClientResult result = await GetBatchAsync(_batchId, _cancellationToken.ToRequestOptions()).ConfigureAwait(false); - - _current = result; - _hasNext = HasNext(result); - - return true; - } - - // TODO: handle Dispose and DisposeAsync using proper patterns? - ValueTask IAsyncDisposable.DisposeAsync() => default; - - #endregion - - private bool HasNext(ClientResult result) - { - PipelineResponse response = result.GetRawResponse(); - - // TODO: don't parse JsonDocument twice if possible - using JsonDocument doc = JsonDocument.Parse(response.Content); - string? status = doc.RootElement.GetProperty("status"u8).GetString(); - - bool isComplete = status == "completed" || - status == "cancelled" || - status == "expired" || - status == "failed"; - - return !isComplete; - } - - // Generated methods - - /// - /// [Protocol Method] Retrieves a batch. - /// - /// The ID of the batch to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task GetBatchAsync(string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateRetrieveBatchRequest(batchId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Retrieves a batch. - /// - /// The ID of the batch to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult GetBatch(string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateRetrieveBatchRequest(batchId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - internal PipelineMessage CreateRetrieveBatchRequest(string batchId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/batches/", false); - uri.AppendPath(batchId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - private static PipelineMessageClassifier? _pipelineMessageClassifier200; - private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); -} diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs b/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs index c95cec02..d016cfe3 100644 --- a/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs +++ b/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs @@ -50,40 +50,6 @@ internal VectorStoreFileBatchOperation( public override bool IsCompleted { get; protected set; } - // These are replaced when LRO is evolved to have conveniences - //public override async Task WaitAsync(CancellationToken cancellationToken = default) - //{ - // IAsyncEnumerator enumerator = - // new VectorStoreFileBatchOperationUpdateEnumerator( - // _pipeline, _endpoint, _vectorStoreId, _batchId, _options); - - // while (await enumerator.MoveNextAsync().ConfigureAwait(false)) - // { - // ApplyUpdate(enumerator.Current); - - // cancellationToken.ThrowIfCancellationRequested(); - - // // TODO: Plumb through cancellation token - // await _pollingInterval.WaitAsync(); - // } - //} - - //public override void Wait(CancellationToken cancellationToken = default) - //{ - // IEnumerator enumerator = - // new VectorStoreFileBatchOperationUpdateEnumerator( - // _pipeline, _endpoint, _vectorStoreId, _batchId, _options); - - // while (enumerator.MoveNext()) - // { - // ApplyUpdate(enumerator.Current); - - // cancellationToken.ThrowIfCancellationRequested(); - - // _pollingInterval.Wait(); - // } - //} - private void ApplyUpdate(ClientResult result) { PipelineResponse response = result.GetRawResponse(); From 136f11a39cf35d83b5247a4bcf177ecd8a671645 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Mon, 5 Aug 2024 17:01:23 -0700 Subject: [PATCH 04/14] remove update enumerators from LRO implementation --- .../BatchOperation.Protocol.cs | 2 + .../FineTuningOperation.Protocol.cs | 22 +-- ...uningOperationUpdateEnumerator.Protocol.cs | 170 ----------------- .../VectorStoreFileBatchOperation.cs | 24 +-- ...BatchOperationUpdateEnumerator.Protocol.cs | 175 ------------------ ...StoreFileBatchOperationUpdateEnumerator.cs | 54 ------ 6 files changed, 22 insertions(+), 425 deletions(-) delete mode 100644 src/To.Be.Generated/FineTuningOperationUpdateEnumerator.Protocol.cs delete mode 100644 src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.Protocol.cs delete mode 100644 src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.cs diff --git a/src/To.Be.Generated/BatchOperation.Protocol.cs b/src/To.Be.Generated/BatchOperation.Protocol.cs index 64504c91..f513960c 100644 --- a/src/To.Be.Generated/BatchOperation.Protocol.cs +++ b/src/To.Be.Generated/BatchOperation.Protocol.cs @@ -62,6 +62,8 @@ public override void WaitForCompletion(CancellationToken cancellationToken = def { while (!IsCompleted) { + cancellationToken.ThrowIfCancellationRequested(); + _pollingInterval.Wait(); ClientResult result = GetBatch(_batchId, cancellationToken.ToRequestOptions()); diff --git a/src/To.Be.Generated/FineTuningOperation.Protocol.cs b/src/To.Be.Generated/FineTuningOperation.Protocol.cs index c4a6dd84..60aa0d80 100644 --- a/src/To.Be.Generated/FineTuningOperation.Protocol.cs +++ b/src/To.Be.Generated/FineTuningOperation.Protocol.cs @@ -43,29 +43,27 @@ internal FineTuningOperation( public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) { - IAsyncEnumerator enumerator = new FineTuningOperationUpdateEnumerator( - _pipeline, _endpoint, _jobId, cancellationToken); - - while (await enumerator.MoveNextAsync().ConfigureAwait(false)) + while (!IsCompleted) { - ApplyUpdate(enumerator.Current); - await _pollingInterval.WaitAsync(cancellationToken); + + ClientResult result = await GetJobAsync(_jobId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + + ApplyUpdate(result); } } public override void WaitForCompletion(CancellationToken cancellationToken = default) { - IEnumerator enumerator = new FineTuningOperationUpdateEnumerator( - _pipeline, _endpoint, _jobId, cancellationToken); - - while (enumerator.MoveNext()) + while (!IsCompleted) { - ApplyUpdate(enumerator.Current); - cancellationToken.ThrowIfCancellationRequested(); _pollingInterval.Wait(); + + ClientResult result = GetJob(_jobId, cancellationToken.ToRequestOptions()); + + ApplyUpdate(result); } } diff --git a/src/To.Be.Generated/FineTuningOperationUpdateEnumerator.Protocol.cs b/src/To.Be.Generated/FineTuningOperationUpdateEnumerator.Protocol.cs deleted file mode 100644 index 29d75f8e..00000000 --- a/src/To.Be.Generated/FineTuningOperationUpdateEnumerator.Protocol.cs +++ /dev/null @@ -1,170 +0,0 @@ -using System; -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Collections; -using System.Collections.Generic; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -#nullable enable - -namespace OpenAI.FineTuning; - -internal partial class FineTuningOperationUpdateEnumerator : - IAsyncEnumerator, - IEnumerator -{ - private readonly ClientPipeline _pipeline; - private readonly Uri _endpoint; - private readonly CancellationToken _cancellationToken; - - private readonly string _jobId; - - private ClientResult? _current; - private bool _hasNext = true; - - public FineTuningOperationUpdateEnumerator( - ClientPipeline pipeline, - Uri endpoint, - string jobId, - CancellationToken cancellationToken) - { - _pipeline = pipeline; - _endpoint = endpoint; - - _jobId = jobId; - - _cancellationToken = cancellationToken; - } - - public ClientResult Current => _current!; - - #region IEnumerator methods - - object IEnumerator.Current => _current!; - - bool IEnumerator.MoveNext() - { - if (!_hasNext) - { - _current = null; - return false; - } - - ClientResult result = GetJob(_jobId, _cancellationToken.ToRequestOptions()); - - _current = result; - _hasNext = HasNext(result); - - return true; - } - - void IEnumerator.Reset() => _current = null; - - void IDisposable.Dispose() { } - - #endregion - - #region IAsyncEnumerator methods - - ClientResult IAsyncEnumerator.Current => _current!; - - public async ValueTask MoveNextAsync() - { - if (!_hasNext) - { - _current = null; - return false; - } - - ClientResult result = await GetJobAsync(_jobId, _cancellationToken.ToRequestOptions()).ConfigureAwait(false); - - _current = result; - _hasNext = HasNext(result); - - return true; - } - - // TODO: handle Dispose and DisposeAsync using proper patterns? - ValueTask IAsyncDisposable.DisposeAsync() => default; - - #endregion - - private bool HasNext(ClientResult result) - { - PipelineResponse response = result.GetRawResponse(); - - // TODO: don't parse JsonDocument twice if possible - using JsonDocument doc = JsonDocument.Parse(response.Content); - string? status = doc.RootElement.GetProperty("status"u8).GetString(); - - bool isComplete = status == "succeeded" || - status == "failed" || - status == "cancelled"; - - return !isComplete; - } - - // Generated methods - - /// - /// [Protocol Method] Get info about a fine-tuning job. - /// - /// [Learn more about fine-tuning](/docs/guides/fine-tuning) - /// - /// The ID of the fine-tuning job. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task GetJobAsync(string jobId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateRetrieveFineTuningJobRequest(jobId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - // CUSTOM: - // - Renamed. - // - Edited doc comment. - /// - /// [Protocol Method] Get info about a fine-tuning job. - /// - /// [Learn more about fine-tuning](/docs/guides/fine-tuning) - /// - /// The ID of the fine-tuning job. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult GetJob(string jobId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateRetrieveFineTuningJobRequest(jobId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - internal PipelineMessage CreateRetrieveFineTuningJobRequest(string fineTuningJobId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/fine_tuning/jobs/", false); - uri.AppendPath(fineTuningJobId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - private static PipelineMessageClassifier? _pipelineMessageClassifier200; - private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); -} diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperation.cs b/src/To.Be.Generated/VectorStoreFileBatchOperation.cs index e6a3e6bf..0ee592bb 100644 --- a/src/To.Be.Generated/VectorStoreFileBatchOperation.cs +++ b/src/To.Be.Generated/VectorStoreFileBatchOperation.cs @@ -48,31 +48,27 @@ internal VectorStoreFileBatchOperation( public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) { - IAsyncEnumerator> enumerator = - new VectorStoreFileBatchOperationUpdateEnumerator( - _pipeline, _endpoint, _vectorStoreId, _batchId, cancellationToken); - - while (await enumerator.MoveNextAsync().ConfigureAwait(false)) + while (!IsCompleted) { - ApplyUpdate(enumerator.Current); - await _pollingInterval.WaitAsync(cancellationToken); + + ClientResult result = await GetBatchFileJobAsync(cancellationToken).ConfigureAwait(false); + + ApplyUpdate(result); } } public override void WaitForCompletion(CancellationToken cancellationToken = default) { - IEnumerator> enumerator = - new VectorStoreFileBatchOperationUpdateEnumerator( - _pipeline, _endpoint, _vectorStoreId, _batchId, cancellationToken); - - while (enumerator.MoveNext()) + while (!IsCompleted) { - ApplyUpdate(enumerator.Current); - cancellationToken.ThrowIfCancellationRequested(); _pollingInterval.Wait(); + + ClientResult result = GetBatchFileJob(cancellationToken); + + ApplyUpdate(result); } } diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.Protocol.cs b/src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.Protocol.cs deleted file mode 100644 index bf3b1f1a..00000000 --- a/src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.Protocol.cs +++ /dev/null @@ -1,175 +0,0 @@ -using System; -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -#nullable enable - -namespace OpenAI.VectorStores; - -internal partial class VectorStoreFileBatchOperationUpdateEnumerator : - IAsyncEnumerator, - IEnumerator -{ - private readonly ClientPipeline _pipeline; - private readonly Uri _endpoint; - private readonly CancellationToken _cancellationToken; - - private readonly string _vectorStoreId; - private readonly string _batchId; - - private ClientResult? _current; - private bool _hasNext = true; - - public VectorStoreFileBatchOperationUpdateEnumerator( - ClientPipeline pipeline, - Uri endpoint, - string vectorStoreId, - string batchId, - CancellationToken cancellationToken) - { - _pipeline = pipeline; - _endpoint = endpoint; - - _vectorStoreId = vectorStoreId; - _batchId = batchId; - - _cancellationToken = cancellationToken; - } - - public ClientResult Current => _current!; - - #region IEnumerator methods - - object IEnumerator.Current => _current!; - - bool IEnumerator.MoveNext() - { - if (!_hasNext) - { - _current = null; - return false; - } - - ClientResult result = GetBatchFileJob(_vectorStoreId, _batchId, _cancellationToken.ToRequestOptions()); - - _current = result; - _hasNext = HasNext(result); - - return true; - } - - void IEnumerator.Reset() => _current = null; - - void IDisposable.Dispose() { } - - #endregion - - #region IAsyncEnumerator methods - - ClientResult IAsyncEnumerator.Current => _current!; - - public async ValueTask MoveNextAsync() - { - if (!_hasNext) - { - _current = null; - return false; - } - - ClientResult result = await GetBatchFileJobAsync(_vectorStoreId, _batchId, _cancellationToken.ToRequestOptions()).ConfigureAwait(false); - - _current = result; - _hasNext = HasNext(result); - - return true; - } - - // TODO: handle Dispose and DisposeAsync using proper patterns? - ValueTask IAsyncDisposable.DisposeAsync() => default; - - #endregion - - private bool HasNext(ClientResult result) - { - PipelineResponse response = result.GetRawResponse(); - - // TODO: don't parse JsonDocument twice if possible - using JsonDocument doc = JsonDocument.Parse(response.Content); - string? status = doc.RootElement.GetProperty("status"u8).GetString(); - - bool isComplete = status == "completed" || - status == "cancelled" || - status == "failed"; - - return !isComplete; - } - - // Generated methods - - /// - /// [Protocol Method] Retrieves a vector store file batch. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch being retrieved. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task GetBatchFileJobAsync(string vectorStoreId, string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(vectorStoreId, batchId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Retrieves a vector store file batch. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch being retrieved. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult GetBatchFileJob(string vectorStoreId, string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(vectorStoreId, batchId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - internal PipelineMessage CreateGetVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/vector_stores/", false); - uri.AppendPath(vectorStoreId, true); - uri.AppendPath("/file_batches/", false); - uri.AppendPath(batchId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - private static PipelineMessageClassifier? _pipelineMessageClassifier200; - private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); -} diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.cs b/src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.cs deleted file mode 100644 index c901c63d..00000000 --- a/src/To.Be.Generated/VectorStoreFileBatchOperationUpdateEnumerator.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Collections.Generic; - -#nullable enable - -namespace OpenAI.VectorStores; - -internal partial class VectorStoreFileBatchOperationUpdateEnumerator : - IAsyncEnumerator>, - IEnumerator> -{ - #region IEnumerator> methods - - ClientResult IEnumerator>.Current - { - get - { - if (Current is null) - { - return default!; - } - - return GetUpdateFromResult(Current); - } - } - - #endregion - - #region IAsyncEnumerator> methods - - ClientResult IAsyncEnumerator>.Current - { - get - { - if (Current is null) - { - return default!; - } - - return GetUpdateFromResult(Current); - } - } - - #endregion - - // Methods used by convenience implementation - private ClientResult GetUpdateFromResult(ClientResult result) - { - PipelineResponse response = result.GetRawResponse(); - VectorStoreBatchFileJob run = VectorStoreBatchFileJob.FromResponse(response); - return ClientResult.FromValue(run, response); - } -} From 981cf97e73fa84ecbd159b98a8ccc49f3da91c34 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Mon, 5 Aug 2024 17:41:24 -0700 Subject: [PATCH 05/14] add Rehydrate methods --- src/Custom/Batch/BatchClient.Protocol.cs | 4 +- src/Custom/Batch/BatchClient.cs | 2 + .../FineTuning/FineTuningClient.Protocol.cs | 60 +++++++++++++++++++ src/Custom/FineTuning/FineTuningClient.cs | 2 + .../VectorStoreClient.Protocol.cs | 58 ++++++++++++++++++ src/Custom/VectorStores/VectorStoreClient.cs | 2 + .../BatchOperation.Protocol.cs | 33 ++++++++++ .../FineTuningOperation.Protocol.cs | 33 +++++++++- .../VectorStoreFileBatchOperation.Protocol.cs | 1 - .../VectorStoreFileBatchOperation.cs | 38 +++++++++++- 10 files changed, 228 insertions(+), 5 deletions(-) diff --git a/src/Custom/Batch/BatchClient.Protocol.cs b/src/Custom/Batch/BatchClient.Protocol.cs index 24f42025..67676a94 100644 --- a/src/Custom/Batch/BatchClient.Protocol.cs +++ b/src/Custom/Batch/BatchClient.Protocol.cs @@ -94,7 +94,7 @@ public virtual ClientResult GetBatches(string after, int? limit, RequestOptions /// is an empty string, and was expected to be non-empty. /// Service returned a non-success status code. /// The response returned from the service. - public virtual async Task GetBatchAsync(string batchId, RequestOptions options) + internal virtual async Task GetBatchAsync(string batchId, RequestOptions options) { Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); @@ -111,7 +111,7 @@ public virtual async Task GetBatchAsync(string batchId, RequestOpt /// is an empty string, and was expected to be non-empty. /// Service returned a non-success status code. /// The response returned from the service. - public virtual ClientResult GetBatch(string batchId, RequestOptions options) + internal virtual ClientResult GetBatch(string batchId, RequestOptions options) { Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); diff --git a/src/Custom/Batch/BatchClient.cs b/src/Custom/Batch/BatchClient.cs index a5c75e9a..6a00166e 100644 --- a/src/Custom/Batch/BatchClient.cs +++ b/src/Custom/Batch/BatchClient.cs @@ -19,6 +19,8 @@ namespace OpenAI.Batch; [CodeGenSuppress("GetBatchesAsync", typeof(string), typeof(int?))] public partial class BatchClient { + internal Uri Endpoint => _endpoint; + /// /// Initializes a new instance of that will use an API key when authenticating. /// diff --git a/src/Custom/FineTuning/FineTuningClient.Protocol.cs b/src/Custom/FineTuning/FineTuningClient.Protocol.cs index a42379a9..202afc13 100644 --- a/src/Custom/FineTuning/FineTuningClient.Protocol.cs +++ b/src/Custom/FineTuning/FineTuningClient.Protocol.cs @@ -131,4 +131,64 @@ public virtual ClientResult GetJobs(string after, int? limit, RequestOptions opt using PipelineMessage message = CreateGetPaginatedFineTuningJobsRequest(after, limit, options); return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Get info about a fine-tuning job. + /// + /// [Learn more about fine-tuning](/docs/guides/fine-tuning) + /// + /// The ID of the fine-tuning job. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + internal virtual async Task GetJobAsync(string jobId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); + + using PipelineMessage message = CreateRetrieveFineTuningJobRequest(jobId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Get info about a fine-tuning job. + /// + /// [Learn more about fine-tuning](/docs/guides/fine-tuning) + /// + /// The ID of the fine-tuning job. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + internal virtual ClientResult GetJob(string jobId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); + + using PipelineMessage message = CreateRetrieveFineTuningJobRequest(jobId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + internal PipelineMessage CreateRetrieveFineTuningJobRequest(string fineTuningJobId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } } diff --git a/src/Custom/FineTuning/FineTuningClient.cs b/src/Custom/FineTuning/FineTuningClient.cs index 6313c783..53ac0b08 100644 --- a/src/Custom/FineTuning/FineTuningClient.cs +++ b/src/Custom/FineTuning/FineTuningClient.cs @@ -24,6 +24,8 @@ public partial class FineTuningClient { // Customization: documented constructors, apply protected visibility + internal Uri Endpoint => _endpoint; + /// /// Initializes a new instance of that will use an API key when authenticating. /// diff --git a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs index b15bb30c..6d55fda7 100644 --- a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs +++ b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs @@ -496,4 +496,62 @@ public virtual VectorStoreFileBatchOperation CreateBatchFileJob( operation.WaitForCompletion(options?.CancellationToken ?? default); return operation; } + + /// + /// [Protocol Method] Retrieves a vector store file batch. + /// + /// The ID of the vector store that the file batch belongs to. + /// The ID of the file batch being retrieved. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + internal virtual async Task GetBatchFileJobAsync(string vectorStoreId, string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(vectorStoreId, batchId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Retrieves a vector store file batch. + /// + /// The ID of the vector store that the file batch belongs to. + /// The ID of the file batch being retrieved. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// or is null. + /// or is an empty string, and was expected to be non-empty. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + internal virtual ClientResult GetBatchFileJob(string vectorStoreId, string batchId, RequestOptions options) + { + Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); + + using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(vectorStoreId, batchId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + internal PipelineMessage CreateGetVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/vector_stores/", false); + uri.AppendPath(vectorStoreId, true); + uri.AppendPath("/file_batches/", false); + uri.AppendPath(batchId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } } diff --git a/src/Custom/VectorStores/VectorStoreClient.cs b/src/Custom/VectorStores/VectorStoreClient.cs index c87d3cbb..1087cfc1 100644 --- a/src/Custom/VectorStores/VectorStoreClient.cs +++ b/src/Custom/VectorStores/VectorStoreClient.cs @@ -38,6 +38,8 @@ namespace OpenAI.VectorStores; [Experimental("OPENAI001")] public partial class VectorStoreClient { + internal Uri Endpoint => _endpoint; + /// /// Initializes a new instance of that will use an API key when authenticating. /// diff --git a/src/To.Be.Generated/BatchOperation.Protocol.cs b/src/To.Be.Generated/BatchOperation.Protocol.cs index f513960c..3fba5b75 100644 --- a/src/To.Be.Generated/BatchOperation.Protocol.cs +++ b/src/To.Be.Generated/BatchOperation.Protocol.cs @@ -45,6 +45,38 @@ internal BatchOperation( public override bool IsCompleted { get; protected set; } + public static async Task RehydrateAsync(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + BatchOperationToken token = BatchOperationToken.FromToken(rehydrationToken); + + ClientResult result = await client.GetBatchAsync(token.BatchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string status = doc.RootElement.GetProperty("status"u8).GetString()!; + + return new BatchOperation(client.Pipeline, client.Endpoint, token.BatchId, status, response); + } + + public static BatchOperation Rehydrate(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + BatchOperationToken token = BatchOperationToken.FromToken(rehydrationToken); + + ClientResult result = client.GetBatch(token.BatchId, cancellationToken.ToRequestOptions()); + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string status = doc.RootElement.GetProperty("status"u8).GetString()!; + + return new BatchOperation(client.Pipeline, client.Endpoint, token.BatchId, status, response); + } + // These are replaced when LRO is evolved to have conveniences public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) { @@ -160,6 +192,7 @@ public virtual ClientResult CancelBatch(string batchId, RequestOptions options) using PipelineMessage message = CreateCancelBatchRequest(batchId, options); return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } + internal PipelineMessage CreateRetrieveBatchRequest(string batchId, RequestOptions options) { var message = _pipeline.CreateMessage(); diff --git a/src/To.Be.Generated/FineTuningOperation.Protocol.cs b/src/To.Be.Generated/FineTuningOperation.Protocol.cs index 60aa0d80..b086acb6 100644 --- a/src/To.Be.Generated/FineTuningOperation.Protocol.cs +++ b/src/To.Be.Generated/FineTuningOperation.Protocol.cs @@ -1,7 +1,6 @@ using System; using System.ClientModel; using System.ClientModel.Primitives; -using System.Collections.Generic; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -41,6 +40,38 @@ internal FineTuningOperation( public override bool IsCompleted { get; protected set; } + public static async Task RehydrateAsync(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + FineTuningOperationToken token = FineTuningOperationToken.FromToken(rehydrationToken); + + ClientResult result = await client.GetJobAsync(token.JobId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string status = doc.RootElement.GetProperty("status"u8).GetString()!; + + return new FineTuningOperation(client.Pipeline, client.Endpoint, token.JobId, status, response); + } + + public static FineTuningOperation Rehydrate(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + FineTuningOperationToken token = FineTuningOperationToken.FromToken(rehydrationToken); + + ClientResult result = client.GetJob(token.JobId, cancellationToken.ToRequestOptions()); + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string status = doc.RootElement.GetProperty("status"u8).GetString()!; + + return new FineTuningOperation(client.Pipeline, client.Endpoint, token.JobId, status, response); + } + public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) { while (!IsCompleted) diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs b/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs index d016cfe3..c5f59536 100644 --- a/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs +++ b/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.ComponentModel; using System.Text.Json; -using System.Threading; using System.Threading.Tasks; #nullable enable diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperation.cs b/src/To.Be.Generated/VectorStoreFileBatchOperation.cs index 0ee592bb..4bf612db 100644 --- a/src/To.Be.Generated/VectorStoreFileBatchOperation.cs +++ b/src/To.Be.Generated/VectorStoreFileBatchOperation.cs @@ -1,7 +1,7 @@ using System; using System.ClientModel; using System.ClientModel.Primitives; -using System.Collections.Generic; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -46,6 +46,42 @@ internal VectorStoreFileBatchOperation( public string VectorStoreId { get => _vectorStoreId; } public string BatchId { get => _batchId; } +#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + public static async Task RehydrateAsync(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) +#pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + VectorStoreFileBatchOperationToken token = VectorStoreFileBatchOperationToken.FromToken(rehydrationToken); + + ClientResult result = await client.GetBatchFileJobAsync(token.VectorStoreId, token.BatchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string status = doc.RootElement.GetProperty("status"u8).GetString()!; + + return new VectorStoreFileBatchOperation(client.Pipeline, client.Endpoint, token.VectorStoreId, token.BatchId, status, response); + } + +#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + public static VectorStoreFileBatchOperation Rehydrate(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) +#pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + VectorStoreFileBatchOperationToken token = VectorStoreFileBatchOperationToken.FromToken(rehydrationToken); + + ClientResult result = client.GetBatchFileJob(token.VectorStoreId, token.BatchId, cancellationToken.ToRequestOptions()); + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string status = doc.RootElement.GetProperty("status"u8).GetString()!; + + return new VectorStoreFileBatchOperation(client.Pipeline, client.Endpoint, token.VectorStoreId, token.BatchId, status, response); + } + public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) { while (!IsCompleted) From 15f10b92b933493980fa4ac3ebc4cd9e6f7dd057 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Tue, 6 Aug 2024 09:00:04 -0700 Subject: [PATCH 06/14] misc tidy up --- .../FineTuning/FineTuningClient.Protocol.cs | 16 ---------------- .../VectorStoreClient.Convenience.cs | 12 ++++-------- .../VectorStores/VectorStoreClient.Protocol.cs | 18 ------------------ src/Custom/VectorStores/VectorStoreClient.cs | 4 ++++ src/Generated/FineTuningClient.cs | 16 ++++++++++++++++ src/Generated/VectorStoreClient.cs | 18 ++++++++++++++++++ .../FineTuningOperation.Protocol.cs | 1 - 7 files changed, 42 insertions(+), 43 deletions(-) diff --git a/src/Custom/FineTuning/FineTuningClient.Protocol.cs b/src/Custom/FineTuning/FineTuningClient.Protocol.cs index 202afc13..5bd7ddac 100644 --- a/src/Custom/FineTuning/FineTuningClient.Protocol.cs +++ b/src/Custom/FineTuning/FineTuningClient.Protocol.cs @@ -175,20 +175,4 @@ internal virtual ClientResult GetJob(string jobId, RequestOptions options) using PipelineMessage message = CreateRetrieveFineTuningJobRequest(jobId, options); return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - - internal PipelineMessage CreateRetrieveFineTuningJobRequest(string fineTuningJobId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/fine_tuning/jobs/", false); - uri.AppendPath(fineTuningJobId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } } diff --git a/src/Custom/VectorStores/VectorStoreClient.Convenience.cs b/src/Custom/VectorStores/VectorStoreClient.Convenience.cs index 4148a8c1..cd0a9926 100644 --- a/src/Custom/VectorStores/VectorStoreClient.Convenience.cs +++ b/src/Custom/VectorStores/VectorStoreClient.Convenience.cs @@ -167,24 +167,20 @@ public virtual ClientResult RemoveFileFromStore(VectorStore vectorStore, O /// /// Begins a batch job to associate multiple jobs with a vector store, beginning the ingestion process. /// + /// TODO /// The vector store to associate files with. /// The files to associate with the vector store. /// A instance representing the batch operation. - public virtual Task CreateBatchFileJobAsync( - ReturnWhen returnWhen, - VectorStore vectorStore, - IEnumerable files) + public virtual Task CreateBatchFileJobAsync(ReturnWhen returnWhen, VectorStore vectorStore, IEnumerable files) => CreateBatchFileJobAsync(returnWhen, vectorStore?.Id, files?.Select(file => file.Id)); /// /// Begins a batch job to associate multiple jobs with a vector store, beginning the ingestion process. /// + /// TODO /// The vector store to associate files with. /// The files to associate with the vector store. /// A instance representing the batch operation. - public virtual VectorStoreFileBatchOperation CreateBatchFileJob( - ReturnWhen returnWhen, - VectorStore vectorStore, - IEnumerable files) + public virtual VectorStoreFileBatchOperation CreateBatchFileJob(ReturnWhen returnWhen, VectorStore vectorStore, IEnumerable files) => CreateBatchFileJob(returnWhen, vectorStore?.Id, files?.Select(file => file.Id)); } diff --git a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs index 6d55fda7..92fda965 100644 --- a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs +++ b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs @@ -536,22 +536,4 @@ internal virtual ClientResult GetBatchFileJob(string vectorStoreId, string batch using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(vectorStoreId, batchId, options); return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - - internal PipelineMessage CreateGetVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/vector_stores/", false); - uri.AppendPath(vectorStoreId, true); - uri.AppendPath("/file_batches/", false); - uri.AppendPath(batchId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } } diff --git a/src/Custom/VectorStores/VectorStoreClient.cs b/src/Custom/VectorStores/VectorStoreClient.cs index 1087cfc1..99e522fa 100644 --- a/src/Custom/VectorStores/VectorStoreClient.cs +++ b/src/Custom/VectorStores/VectorStoreClient.cs @@ -15,6 +15,10 @@ namespace OpenAI.VectorStores; [CodeGenClient("VectorStores")] [CodeGenSuppress("CreateVectorStoreAsync", typeof(VectorStoreCreationOptions))] [CodeGenSuppress("CreateVectorStore", typeof(VectorStoreCreationOptions))] +[CodeGenSuppress("GetVectorStoreAsync", typeof(string))] +[CodeGenSuppress("GetVectorStore", typeof(string))] +[CodeGenSuppress("ModifyVectorStoreAsync", typeof(string), typeof(VectorStoreModificationOptions))] +[CodeGenSuppress("ModifyVectorStore", typeof(string), typeof(VectorStoreModificationOptions))] [CodeGenSuppress("DeleteVectorStoreAsync", typeof(string))] [CodeGenSuppress("DeleteVectorStore", typeof(string))] [CodeGenSuppress("GetVectorStoresAsync", typeof(int?), typeof(ListOrder?), typeof(string), typeof(string))] diff --git a/src/Generated/FineTuningClient.cs b/src/Generated/FineTuningClient.cs index 1427659e..87c48998 100644 --- a/src/Generated/FineTuningClient.cs +++ b/src/Generated/FineTuningClient.cs @@ -71,6 +71,22 @@ internal PipelineMessage CreateGetPaginatedFineTuningJobsRequest(string after, i return message; } + internal PipelineMessage CreateRetrieveFineTuningJobRequest(string fineTuningJobId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + private static PipelineMessageClassifier _pipelineMessageClassifier200; private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); } diff --git a/src/Generated/VectorStoreClient.cs b/src/Generated/VectorStoreClient.cs index 61cb80aa..408d8d30 100644 --- a/src/Generated/VectorStoreClient.cs +++ b/src/Generated/VectorStoreClient.cs @@ -240,6 +240,24 @@ internal PipelineMessage CreateCreateVectorStoreFileBatchRequest(string vectorSt return message; } + internal PipelineMessage CreateGetVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/vector_stores/", false); + uri.AppendPath(vectorStoreId, true); + uri.AppendPath("/file_batches/", false); + uri.AppendPath(batchId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + private static PipelineMessageClassifier _pipelineMessageClassifier200; private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); } diff --git a/src/To.Be.Generated/FineTuningOperation.Protocol.cs b/src/To.Be.Generated/FineTuningOperation.Protocol.cs index b086acb6..f2bdbc2e 100644 --- a/src/To.Be.Generated/FineTuningOperation.Protocol.cs +++ b/src/To.Be.Generated/FineTuningOperation.Protocol.cs @@ -118,7 +118,6 @@ private static bool GetIsCompleted(string? status) // Generated protocol methods - // CUSTOM: // - Renamed. // - Edited doc comment. From 71c64374d8e2bdcb4c303c57812f0b36aa8fd933 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Tue, 6 Aug 2024 10:14:27 -0700 Subject: [PATCH 07/14] update PollingInterval to respect Retry-After header; add polling overloads to WaitForCompletion --- .../VectorStoreClient.Protocol.cs | 14 ++--- .../BatchOperation.Protocol.cs | 36 ++++++++----- .../FineTuningOperation.Protocol.cs | 33 +++++++++--- .../Internal/PollingInterval.cs | 53 ++++++++++++++++--- .../VectorStoreFileBatchOperation.Protocol.cs | 46 +--------------- .../VectorStoreFileBatchOperation.cs | 53 ++++++++++--------- 6 files changed, 130 insertions(+), 105 deletions(-) diff --git a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs index 92fda965..bcfbd794 100644 --- a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs +++ b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs @@ -445,12 +445,9 @@ public virtual async Task CreateBatchFileJobAsync using PipelineMessage message = CreateCreateVectorStoreFileBatchRequest(vectorStoreId, content, options); PipelineResponse response = await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false); + VectorStoreBatchFileJob job = VectorStoreBatchFileJob.FromResponse(response); - using JsonDocument doc = JsonDocument.Parse(response.Content); - string batchId = doc.RootElement.GetProperty("id"u8).GetString(); - string status = doc.RootElement.GetProperty("status"u8).GetString(); - - VectorStoreFileBatchOperation operation = new VectorStoreFileBatchOperation(_pipeline, _endpoint, vectorStoreId, batchId, status, response); + VectorStoreFileBatchOperation operation = new(_pipeline, _endpoint, ClientResult.FromValue(job, response)); if (returnWhen == ReturnWhen.Started) { return operation; @@ -482,12 +479,9 @@ public virtual VectorStoreFileBatchOperation CreateBatchFileJob( using PipelineMessage message = CreateCreateVectorStoreFileBatchRequest(vectorStoreId, content, options); PipelineResponse response = _pipeline.ProcessMessage(message, options); + VectorStoreBatchFileJob job = VectorStoreBatchFileJob.FromResponse(response); - using JsonDocument doc = JsonDocument.Parse(response.Content); - string batchId = doc.RootElement.GetProperty("id"u8).GetString(); - string status = doc.RootElement.GetProperty("status"u8).GetString(); - - VectorStoreFileBatchOperation operation = new VectorStoreFileBatchOperation(_pipeline, _endpoint, vectorStoreId, batchId, status, response); + VectorStoreFileBatchOperation operation = new(_pipeline, _endpoint, ClientResult.FromValue(job, response)); if (returnWhen == ReturnWhen.Started) { return operation; diff --git a/src/To.Be.Generated/BatchOperation.Protocol.cs b/src/To.Be.Generated/BatchOperation.Protocol.cs index 3fba5b75..e3b7d9e5 100644 --- a/src/To.Be.Generated/BatchOperation.Protocol.cs +++ b/src/To.Be.Generated/BatchOperation.Protocol.cs @@ -9,7 +9,6 @@ namespace OpenAI.Batch; -// Protocol version public partial class BatchOperation : OperationResult { private readonly ClientPipeline _pipeline; @@ -17,10 +16,8 @@ public partial class BatchOperation : OperationResult private readonly string _batchId; - private PollingInterval _pollingInterval; + private PollingInterval? _pollingInterval; - // For use with protocol methods where the response has been obtained prior - // to creation of the LRO instance. internal BatchOperation( ClientPipeline pipeline, Uri endpoint, @@ -31,13 +28,9 @@ internal BatchOperation( { _pipeline = pipeline; _endpoint = endpoint; - _batchId = batchId; IsCompleted = GetIsCompleted(status); - - _pollingInterval = new(); - RehydrationToken = new BatchOperationToken(batchId); } @@ -77,12 +70,15 @@ public static BatchOperation Rehydrate(BatchClient client, ContinuationToken reh return new BatchOperation(client.Pipeline, client.Endpoint, token.BatchId, status, response); } - // These are replaced when LRO is evolved to have conveniences public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) { + _pollingInterval ??= new(); + while (!IsCompleted) { - await _pollingInterval.WaitAsync(cancellationToken); + PipelineResponse response = GetRawResponse(); + + await _pollingInterval.WaitAsync(response, cancellationToken); ClientResult result = await GetBatchAsync(_batchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); @@ -90,13 +86,22 @@ public override async Task WaitForCompletionAsync(CancellationToken cancellation } } + public async Task WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken = default) + { + _pollingInterval = new(pollingInterval); + + await WaitForCompletionAsync(cancellationToken).ConfigureAwait(false); + } + public override void WaitForCompletion(CancellationToken cancellationToken = default) { + _pollingInterval ??= new(); + while (!IsCompleted) { - cancellationToken.ThrowIfCancellationRequested(); + PipelineResponse response = GetRawResponse(); - _pollingInterval.Wait(); + _pollingInterval.Wait(response, cancellationToken); ClientResult result = GetBatch(_batchId, cancellationToken.ToRequestOptions()); @@ -104,6 +109,13 @@ public override void WaitForCompletion(CancellationToken cancellationToken = def } } + public void WaitForCompletion(TimeSpan pollingInterval, CancellationToken cancellationToken = default) + { + _pollingInterval = new(pollingInterval); + + WaitForCompletion(cancellationToken); + } + private void ApplyUpdate(ClientResult result) { PipelineResponse response = result.GetRawResponse(); diff --git a/src/To.Be.Generated/FineTuningOperation.Protocol.cs b/src/To.Be.Generated/FineTuningOperation.Protocol.cs index f2bdbc2e..efba71bb 100644 --- a/src/To.Be.Generated/FineTuningOperation.Protocol.cs +++ b/src/To.Be.Generated/FineTuningOperation.Protocol.cs @@ -16,7 +16,7 @@ public partial class FineTuningOperation : OperationResult private readonly string _jobId; - private PollingInterval _pollingInterval; + private PollingInterval? _pollingInterval; internal FineTuningOperation( ClientPipeline pipeline, @@ -27,12 +27,9 @@ internal FineTuningOperation( { _pipeline = pipeline; _endpoint = endpoint; - _jobId = jobId; - IsCompleted = GetIsCompleted(status); - - _pollingInterval = new(); + IsCompleted = GetIsCompleted(status); RehydrationToken = new FineTuningOperationToken(jobId); } @@ -74,9 +71,13 @@ public static FineTuningOperation Rehydrate(FineTuningClient client, Continuatio public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) { + _pollingInterval ??= new(); + while (!IsCompleted) { - await _pollingInterval.WaitAsync(cancellationToken); + PipelineResponse response = GetRawResponse(); + + await _pollingInterval.WaitAsync(response, cancellationToken); ClientResult result = await GetJobAsync(_jobId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); @@ -84,13 +85,22 @@ public override async Task WaitForCompletionAsync(CancellationToken cancellation } } + public async Task WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken = default) + { + _pollingInterval = new(pollingInterval); + + await WaitForCompletionAsync(cancellationToken).ConfigureAwait(false); + } + public override void WaitForCompletion(CancellationToken cancellationToken = default) { + _pollingInterval ??= new(); + while (!IsCompleted) { - cancellationToken.ThrowIfCancellationRequested(); + PipelineResponse response = GetRawResponse(); - _pollingInterval.Wait(); + _pollingInterval.Wait(response, cancellationToken); ClientResult result = GetJob(_jobId, cancellationToken.ToRequestOptions()); @@ -98,6 +108,13 @@ public override void WaitForCompletion(CancellationToken cancellationToken = def } } + public void WaitForCompletion(TimeSpan pollingInterval, CancellationToken cancellationToken = default) + { + _pollingInterval = new(pollingInterval); + + WaitForCompletion(cancellationToken); + } + private void ApplyUpdate(ClientResult result) { PipelineResponse response = result.GetRawResponse(); diff --git a/src/To.Be.Generated/Internal/PollingInterval.cs b/src/To.Be.Generated/Internal/PollingInterval.cs index d159aabd..7f593736 100644 --- a/src/To.Be.Generated/Internal/PollingInterval.cs +++ b/src/To.Be.Generated/Internal/PollingInterval.cs @@ -1,4 +1,5 @@ using System; +using System.ClientModel.Primitives; using System.Threading; using System.Threading.Tasks; @@ -8,22 +9,62 @@ namespace OpenAI; internal class PollingInterval { - private const int DefaultWaitMilliseconds = 1000; + private const string RetryAfterHeaderName = "Retry-After"; + private static readonly TimeSpan DefaultDelay = TimeSpan.FromSeconds(0.8); private readonly TimeSpan _interval; public PollingInterval(TimeSpan? interval = default) { - _interval = interval ?? new TimeSpan(DefaultWaitMilliseconds); + _interval = interval ?? DefaultDelay; } - public async Task WaitAsync(CancellationToken cancellationToken) + public async Task WaitAsync(PipelineResponse response, CancellationToken cancellationToken) { - await Task.Delay(_interval, cancellationToken); + TimeSpan delay = GetDelay(response); + + await Task.Delay(delay, cancellationToken); } - public void Wait() + public void Wait(PipelineResponse response, CancellationToken cancellationToken) { - Thread.Sleep(_interval); + TimeSpan delay = GetDelay(response); + + if (!cancellationToken.CanBeCanceled) + { + Thread.Sleep(delay); + return; + } + + if (cancellationToken.WaitHandle.WaitOne(delay)) + { + cancellationToken.ThrowIfCancellationRequested(); + } + } + + private TimeSpan GetDelay(PipelineResponse response) + => TryGetRetryAfter(response, out TimeSpan retryAfter) && retryAfter > _interval ? + retryAfter : _interval; + + private static bool TryGetRetryAfter(PipelineResponse response, out TimeSpan value) + { + // See: https://www.rfc-editor.org/rfc/rfc7231#section-7.1.3 + if (response.Headers.TryGetValue(RetryAfterHeaderName, out string? retryAfter)) + { + if (int.TryParse(retryAfter, out var delaySeconds)) + { + value = TimeSpan.FromSeconds(delaySeconds); + return true; + } + + if (DateTimeOffset.TryParse(retryAfter, out DateTimeOffset retryAfterDate)) + { + value = retryAfterDate - DateTimeOffset.Now; + return true; + } + } + + value = default; + return false; } } diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs b/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs index c5f59536..859828da 100644 --- a/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs +++ b/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs @@ -3,14 +3,12 @@ using System.ClientModel.Primitives; using System.Collections.Generic; using System.ComponentModel; -using System.Text.Json; using System.Threading.Tasks; #nullable enable namespace OpenAI.VectorStores; -// Protocol version public partial class VectorStoreFileBatchOperation : OperationResult { private readonly ClientPipeline _pipeline; @@ -19,54 +17,12 @@ public partial class VectorStoreFileBatchOperation : OperationResult private readonly string _vectorStoreId; private readonly string _batchId; - private PollingInterval _pollingInterval; - - // For use with protocol methods where the response has been obtained prior - // to creation of the LRO instance. - internal VectorStoreFileBatchOperation( - ClientPipeline pipeline, - Uri endpoint, - string vectorStoreId, - string batchId, - string status, - PipelineResponse response) - : base(response) - { - _pipeline = pipeline; - _endpoint = endpoint; - - _vectorStoreId = vectorStoreId; - _batchId = batchId; - - IsCompleted = GetIsCompleted(status); - - _pollingInterval = new(); - - RehydrationToken = new VectorStoreFileBatchOperationToken(vectorStoreId, batchId); - } + private PollingInterval? _pollingInterval; public override ContinuationToken? RehydrationToken { get; protected set; } public override bool IsCompleted { get; protected set; } - private void ApplyUpdate(ClientResult result) - { - PipelineResponse response = result.GetRawResponse(); - - using JsonDocument doc = JsonDocument.Parse(response.Content); - string? status = doc.RootElement.GetProperty("status"u8).GetString(); - - IsCompleted = GetIsCompleted(status); - SetRawResponse(response); - } - - private static bool GetIsCompleted(string? status) - { - return status == "completed" || - status == "cancelled" || - status == "failed"; - } - // Generated protocol methods /// diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperation.cs b/src/To.Be.Generated/VectorStoreFileBatchOperation.cs index 4bf612db..886ef08c 100644 --- a/src/To.Be.Generated/VectorStoreFileBatchOperation.cs +++ b/src/To.Be.Generated/VectorStoreFileBatchOperation.cs @@ -9,10 +9,8 @@ namespace OpenAI.VectorStores; -// Convenience version public partial class VectorStoreFileBatchOperation : OperationResult { - // Convenience version internal VectorStoreFileBatchOperation( ClientPipeline pipeline, Uri endpoint, @@ -21,25 +19,17 @@ internal VectorStoreFileBatchOperation( { _pipeline = pipeline; _endpoint = endpoint; - + Value = result; Status = Value.Status; - IsCompleted = GetIsCompleted(Value.Status); _vectorStoreId = Value.VectorStoreId; _batchId = Value.BatchId; - _pollingInterval = new(); - + IsCompleted = GetIsCompleted(Value.Status); RehydrationToken = new VectorStoreFileBatchOperationToken(VectorStoreId, BatchId); } - // TODO: interesting question regarding whether these properties should be - // nullable or not. If someone has called the protocol method, do they want - // to pay the perf cost of deserialization? This could capitalize on a - // property on RequestOptions that allows the caller to opt-in to creation - // of convenience models. For now, make them nullable so I don't have to - // pass the model into the constructor from a protocol method. public VectorStoreBatchFileJob? Value { get; private set; } public VectorStoreBatchFileJobStatus? Status { get; private set; } @@ -57,11 +47,9 @@ public static async Task RehydrateAsync(VectorSto ClientResult result = await client.GetBatchFileJobAsync(token.VectorStoreId, token.BatchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); PipelineResponse response = result.GetRawResponse(); + VectorStoreBatchFileJob job = VectorStoreBatchFileJob.FromResponse(response); - using JsonDocument doc = JsonDocument.Parse(response.Content); - string status = doc.RootElement.GetProperty("status"u8).GetString()!; - - return new VectorStoreFileBatchOperation(client.Pipeline, client.Endpoint, token.VectorStoreId, token.BatchId, status, response); + return new VectorStoreFileBatchOperation(client.Pipeline, client.Endpoint, FromValue(job, response)); } #pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -75,39 +63,56 @@ public static VectorStoreFileBatchOperation Rehydrate(VectorStoreClient client, ClientResult result = client.GetBatchFileJob(token.VectorStoreId, token.BatchId, cancellationToken.ToRequestOptions()); PipelineResponse response = result.GetRawResponse(); + VectorStoreBatchFileJob job = VectorStoreBatchFileJob.FromResponse(response); - using JsonDocument doc = JsonDocument.Parse(response.Content); - string status = doc.RootElement.GetProperty("status"u8).GetString()!; - - return new VectorStoreFileBatchOperation(client.Pipeline, client.Endpoint, token.VectorStoreId, token.BatchId, status, response); + return new VectorStoreFileBatchOperation(client.Pipeline, client.Endpoint, FromValue(job, response)); } public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) { + _pollingInterval ??= new(); + while (!IsCompleted) { - await _pollingInterval.WaitAsync(cancellationToken); + PipelineResponse response = GetRawResponse(); + + await _pollingInterval.WaitAsync(response, cancellationToken); ClientResult result = await GetBatchFileJobAsync(cancellationToken).ConfigureAwait(false); ApplyUpdate(result); } } + public async Task WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken = default) + { + _pollingInterval = new(pollingInterval); + + await WaitForCompletionAsync(cancellationToken).ConfigureAwait(false); + } public override void WaitForCompletion(CancellationToken cancellationToken = default) { + _pollingInterval ??= new(); + while (!IsCompleted) { - cancellationToken.ThrowIfCancellationRequested(); + PipelineResponse response = GetRawResponse(); - _pollingInterval.Wait(); + _pollingInterval.Wait(response, cancellationToken); - ClientResult result = GetBatchFileJob(cancellationToken); + ClientResult result = GetBatchFileJob(cancellationToken); ApplyUpdate(result); } } + public void WaitForCompletion(TimeSpan pollingInterval, CancellationToken cancellationToken = default) + { + _pollingInterval = new(pollingInterval); + + WaitForCompletion(cancellationToken); + } + private void ApplyUpdate(ClientResult update) { Value = update; From d4e063108b0d0feda4058030c886ba4edbec3153 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Tue, 6 Aug 2024 10:17:17 -0700 Subject: [PATCH 08/14] move files out of To.Be.Generated folder --- src/{To.Be.Generated => Custom/Batch}/BatchOperation.Protocol.cs | 0 src/{To.Be.Generated => Custom/Batch}/BatchOperationToken.cs | 0 .../FineTuning}/FineTuningOperation.Protocol.cs | 0 .../FineTuning}/FineTuningOperationToken.cs | 0 .../VectorStores}/VectorStoreFileBatchOperation.Protocol.cs | 0 .../VectorStores}/VectorStoreFileBatchOperation.cs | 0 .../VectorStores}/VectorStoreFileBatchOperationToken.cs | 0 src/{To.Be.Generated/Internal => Utility}/PollingInterval.cs | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename src/{To.Be.Generated => Custom/Batch}/BatchOperation.Protocol.cs (100%) rename src/{To.Be.Generated => Custom/Batch}/BatchOperationToken.cs (100%) rename src/{To.Be.Generated => Custom/FineTuning}/FineTuningOperation.Protocol.cs (100%) rename src/{To.Be.Generated => Custom/FineTuning}/FineTuningOperationToken.cs (100%) rename src/{To.Be.Generated => Custom/VectorStores}/VectorStoreFileBatchOperation.Protocol.cs (100%) rename src/{To.Be.Generated => Custom/VectorStores}/VectorStoreFileBatchOperation.cs (100%) rename src/{To.Be.Generated => Custom/VectorStores}/VectorStoreFileBatchOperationToken.cs (100%) rename src/{To.Be.Generated/Internal => Utility}/PollingInterval.cs (100%) diff --git a/src/To.Be.Generated/BatchOperation.Protocol.cs b/src/Custom/Batch/BatchOperation.Protocol.cs similarity index 100% rename from src/To.Be.Generated/BatchOperation.Protocol.cs rename to src/Custom/Batch/BatchOperation.Protocol.cs diff --git a/src/To.Be.Generated/BatchOperationToken.cs b/src/Custom/Batch/BatchOperationToken.cs similarity index 100% rename from src/To.Be.Generated/BatchOperationToken.cs rename to src/Custom/Batch/BatchOperationToken.cs diff --git a/src/To.Be.Generated/FineTuningOperation.Protocol.cs b/src/Custom/FineTuning/FineTuningOperation.Protocol.cs similarity index 100% rename from src/To.Be.Generated/FineTuningOperation.Protocol.cs rename to src/Custom/FineTuning/FineTuningOperation.Protocol.cs diff --git a/src/To.Be.Generated/FineTuningOperationToken.cs b/src/Custom/FineTuning/FineTuningOperationToken.cs similarity index 100% rename from src/To.Be.Generated/FineTuningOperationToken.cs rename to src/Custom/FineTuning/FineTuningOperationToken.cs diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs b/src/Custom/VectorStores/VectorStoreFileBatchOperation.Protocol.cs similarity index 100% rename from src/To.Be.Generated/VectorStoreFileBatchOperation.Protocol.cs rename to src/Custom/VectorStores/VectorStoreFileBatchOperation.Protocol.cs diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperation.cs b/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs similarity index 100% rename from src/To.Be.Generated/VectorStoreFileBatchOperation.cs rename to src/Custom/VectorStores/VectorStoreFileBatchOperation.cs diff --git a/src/To.Be.Generated/VectorStoreFileBatchOperationToken.cs b/src/Custom/VectorStores/VectorStoreFileBatchOperationToken.cs similarity index 100% rename from src/To.Be.Generated/VectorStoreFileBatchOperationToken.cs rename to src/Custom/VectorStores/VectorStoreFileBatchOperationToken.cs diff --git a/src/To.Be.Generated/Internal/PollingInterval.cs b/src/Utility/PollingInterval.cs similarity index 100% rename from src/To.Be.Generated/Internal/PollingInterval.cs rename to src/Utility/PollingInterval.cs From b672d0619ae02df548b83b822af02d397fe36892 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Tue, 6 Aug 2024 10:42:46 -0700 Subject: [PATCH 09/14] add some doc comments --- src/Custom/Batch/BatchClient.Protocol.cs | 28 +++++++++++++++++++ .../FineTuning/FineTuningClient.Protocol.cs | 18 ++++++++++-- .../VectorStoreClient.Protocol.cs | 16 +++++++++-- src/Custom/VectorStores/VectorStoreClient.cs | 16 +++++++++-- .../VectorStoreFileBatchOperation.cs | 2 +- 5 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/Custom/Batch/BatchClient.Protocol.cs b/src/Custom/Batch/BatchClient.Protocol.cs index 67676a94..7a86359d 100644 --- a/src/Custom/Batch/BatchClient.Protocol.cs +++ b/src/Custom/Batch/BatchClient.Protocol.cs @@ -8,6 +8,20 @@ namespace OpenAI.Batch; public partial class BatchClient { + /// + /// [Protocol Method] Creates and executes a batch from an uploaded file of requests + /// + /// if the + /// method should return when the service has finished running the + /// operation, or if it should return + /// after the operation has been created but may not have completed + /// processing. + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// A that can be used to wait for + /// the operation to complete, or cancel the operation. public virtual async Task CreateBatchAsync( ReturnWhen returnWhen, BinaryContent content, @@ -33,6 +47,20 @@ public virtual async Task CreateBatchAsync( return operation; } + /// + /// [Protocol Method] Creates and executes a batch from an uploaded file of requests + /// + /// if the + /// method should return when the service has finished running the + /// operation, or if it should return + /// after the operation has been created but may not have completed + /// processing. + /// The content to send as the body of the request. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// is null. + /// Service returned a non-success status code. + /// A that can be used to wait for + /// the operation to complete, or cancel the operation. public virtual BatchOperation CreateBatch( ReturnWhen returnWhen, BinaryContent content, diff --git a/src/Custom/FineTuning/FineTuningClient.Protocol.cs b/src/Custom/FineTuning/FineTuningClient.Protocol.cs index 5bd7ddac..448f3c36 100644 --- a/src/Custom/FineTuning/FineTuningClient.Protocol.cs +++ b/src/Custom/FineTuning/FineTuningClient.Protocol.cs @@ -30,11 +30,18 @@ public partial class FineTuningClient /// /// [Learn more about fine-tuning](/docs/guides/fine-tuning) /// + /// if the + /// method should return when the service has finished running the + /// operation, or if it should return + /// after the operation has been created but may not have completed + /// processing. /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// is null. /// Service returned a non-success status code. - /// The response returned from the service. + /// A that can be used to wait for + /// the operation to complete, get information about the fine tuning job, or + /// cancel the operation. public virtual async Task CreateJobAsync( ReturnWhen returnWhen, BinaryContent content, @@ -69,11 +76,18 @@ public virtual async Task CreateJobAsync( /// /// [Learn more about fine-tuning](/docs/guides/fine-tuning) /// + /// if the + /// method should return when the service has finished running the + /// operation, or if it should return + /// after the operation has been created but may not have completed + /// processing. /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// is null. /// Service returned a non-success status code. - /// The response returned from the service. + /// A that can be used to wait for + /// the operation to complete, get information about the fine tuning job, or + /// cancel the operation. public virtual FineTuningOperation CreateJob( ReturnWhen returnWhen, BinaryContent content, diff --git a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs index bcfbd794..a6eb2db4 100644 --- a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs +++ b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs @@ -426,13 +426,19 @@ public virtual ClientResult RemoveFileFromStore(string vectorStoreId, string fil /// /// [Protocol Method] Create a vector store file batch. /// + /// if the + /// method should return when the service has finished running the + /// operation, or if it should return + /// after the operation has been created but may not have completed + /// processing. /// The ID of the vector store for which to create a file batch. /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// or is null. /// is an empty string, and was expected to be non-empty. /// Service returned a non-success status code. - /// The response returned from the service. + /// A that can be used to wait for + /// the operation to complete, get information about the batch file job, or cancel the operation. [EditorBrowsable(EditorBrowsableState.Never)] public virtual async Task CreateBatchFileJobAsync( ReturnWhen returnWhen, @@ -460,13 +466,19 @@ public virtual async Task CreateBatchFileJobAsync /// /// [Protocol Method] Create a vector store file batch. /// + /// if the + /// method should return when the service has finished running the + /// operation, or if it should return + /// after the operation has been created but may not have completed + /// processing. /// The ID of the vector store for which to create a file batch. /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// or is null. /// is an empty string, and was expected to be non-empty. /// Service returned a non-success status code. - /// The response returned from the service. + /// A that can be used to wait for + /// the operation to complete, get information about the batch file job, or cancel the operation. [EditorBrowsable(EditorBrowsableState.Never)] public virtual VectorStoreFileBatchOperation CreateBatchFileJob( ReturnWhen returnWhen, diff --git a/src/Custom/VectorStores/VectorStoreClient.cs b/src/Custom/VectorStores/VectorStoreClient.cs index 99e522fa..6be53f8d 100644 --- a/src/Custom/VectorStores/VectorStoreClient.cs +++ b/src/Custom/VectorStores/VectorStoreClient.cs @@ -542,10 +542,16 @@ public virtual ClientResult RemoveFileFromStore(string vectorStoreId, stri /// /// Begins a batch job to associate multiple jobs with a vector store, beginning the ingestion process. /// + /// if the + /// method should return when the service has finished running the + /// operation, or if it should return + /// after the operation has been created but may not have completed + /// processing. /// The ID of the vector store to associate files with. /// The IDs of the files to associate with the vector store. /// A token that can be used to cancel this method call. - /// A instance representing the batch operation. + /// A that can be used to wait for + /// the operation to complete, get information about the batch file job, or cancel the operation. public virtual async Task CreateBatchFileJobAsync( ReturnWhen returnWhen, string vectorStoreId, @@ -579,10 +585,16 @@ public virtual async Task CreateBatchFileJobAsync /// /// Begins a batch job to associate multiple jobs with a vector store, beginning the ingestion process. /// + /// if the + /// method should return when the service has finished running the + /// operation, or if it should return + /// after the operation has been created but may not have completed + /// processing. /// The ID of the vector store to associate files with. /// The IDs of the files to associate with the vector store. /// A token that can be used to cancel this method call. - /// A instance representing the batch operation. + /// A that can be used to wait for + /// the operation to complete, get information about the batch file job, or cancel the operation. public virtual VectorStoreFileBatchOperation CreateBatchFileJob( ReturnWhen returnWhen, string vectorStoreId, diff --git a/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs b/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs index 886ef08c..5d06555c 100644 --- a/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs +++ b/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs @@ -1,7 +1,6 @@ using System; using System.ClientModel; using System.ClientModel.Primitives; -using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -83,6 +82,7 @@ public override async Task WaitForCompletionAsync(CancellationToken cancellation ApplyUpdate(result); } } + public async Task WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken = default) { _pollingInterval = new(pollingInterval); From 7fd1d21f8cd8c704c60c83fdc21be1799fa17b12 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Tue, 6 Aug 2024 11:37:07 -0700 Subject: [PATCH 10/14] add refdoc comments to public operation types --- src/Custom/Batch/BatchClient.Protocol.cs | 10 +--- src/Custom/Batch/BatchOperation.Protocol.cs | 42 +++++++++++++++ .../FineTuningOperation.Protocol.cs | 41 ++++++++++++++ .../VectorStoreClient.Protocol.cs | 1 - .../VectorStoreFileBatchOperation.Protocol.cs | 5 ++ .../VectorStoreFileBatchOperation.cs | 53 +++++++++++++++++++ 6 files changed, 143 insertions(+), 9 deletions(-) diff --git a/src/Custom/Batch/BatchClient.Protocol.cs b/src/Custom/Batch/BatchClient.Protocol.cs index 7a86359d..ad67b013 100644 --- a/src/Custom/Batch/BatchClient.Protocol.cs +++ b/src/Custom/Batch/BatchClient.Protocol.cs @@ -22,10 +22,7 @@ public partial class BatchClient /// Service returned a non-success status code. /// A that can be used to wait for /// the operation to complete, or cancel the operation. - public virtual async Task CreateBatchAsync( - ReturnWhen returnWhen, - BinaryContent content, - RequestOptions options = null) + public virtual async Task CreateBatchAsync(ReturnWhen returnWhen, BinaryContent content, RequestOptions options = null) { Argument.AssertNotNull(content, nameof(content)); @@ -61,10 +58,7 @@ public virtual async Task CreateBatchAsync( /// Service returned a non-success status code. /// A that can be used to wait for /// the operation to complete, or cancel the operation. - public virtual BatchOperation CreateBatch( - ReturnWhen returnWhen, - BinaryContent content, - RequestOptions options = null) + public virtual BatchOperation CreateBatch(ReturnWhen returnWhen, BinaryContent content, RequestOptions options = null) { Argument.AssertNotNull(content, nameof(content)); diff --git a/src/Custom/Batch/BatchOperation.Protocol.cs b/src/Custom/Batch/BatchOperation.Protocol.cs index e3b7d9e5..3a88a9c9 100644 --- a/src/Custom/Batch/BatchOperation.Protocol.cs +++ b/src/Custom/Batch/BatchOperation.Protocol.cs @@ -9,6 +9,10 @@ namespace OpenAI.Batch; +/// +/// A long-running operation for executing a batch from an uploaded file of +/// requests. +/// public partial class BatchOperation : OperationResult { private readonly ClientPipeline _pipeline; @@ -34,10 +38,22 @@ internal BatchOperation( RehydrationToken = new BatchOperationToken(batchId); } + /// public override ContinuationToken? RehydrationToken { get; protected set; } + /// public override bool IsCompleted { get; protected set; } + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. public static async Task RehydrateAsync(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) { Argument.AssertNotNull(client, nameof(client)); @@ -54,6 +70,16 @@ public static async Task RehydrateAsync(BatchClient client, Cont return new BatchOperation(client.Pipeline, client.Endpoint, token.BatchId, status, response); } + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. public static BatchOperation Rehydrate(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) { Argument.AssertNotNull(client, nameof(client)); @@ -70,6 +96,7 @@ public static BatchOperation Rehydrate(BatchClient client, ContinuationToken reh return new BatchOperation(client.Pipeline, client.Endpoint, token.BatchId, status, response); } + /// public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) { _pollingInterval ??= new(); @@ -86,6 +113,13 @@ public override async Task WaitForCompletionAsync(CancellationToken cancellation } } + /// + /// Waits for the operation to complete processing on the service. + /// + /// The time to wait between sending requests + /// for status updates from the service. + /// A token that can be used to cancel this + /// method call. public async Task WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken = default) { _pollingInterval = new(pollingInterval); @@ -93,6 +127,7 @@ public async Task WaitForCompletionAsync(TimeSpan pollingInterval, CancellationT await WaitForCompletionAsync(cancellationToken).ConfigureAwait(false); } + /// public override void WaitForCompletion(CancellationToken cancellationToken = default) { _pollingInterval ??= new(); @@ -109,6 +144,13 @@ public override void WaitForCompletion(CancellationToken cancellationToken = def } } + /// + /// Waits for the operation to complete processing on the service. + /// + /// The time to wait between sending requests + /// for status updates from the service. + /// A token that can be used to cancel this + /// method call. public void WaitForCompletion(TimeSpan pollingInterval, CancellationToken cancellationToken = default) { _pollingInterval = new(pollingInterval); diff --git a/src/Custom/FineTuning/FineTuningOperation.Protocol.cs b/src/Custom/FineTuning/FineTuningOperation.Protocol.cs index efba71bb..32f1843c 100644 --- a/src/Custom/FineTuning/FineTuningOperation.Protocol.cs +++ b/src/Custom/FineTuning/FineTuningOperation.Protocol.cs @@ -9,6 +9,9 @@ namespace OpenAI.FineTuning; +/// +/// A long-running operation for creating a new model from a given dataset. +/// public partial class FineTuningOperation : OperationResult { private readonly ClientPipeline _pipeline; @@ -33,10 +36,22 @@ internal FineTuningOperation( RehydrationToken = new FineTuningOperationToken(jobId); } + /// public override ContinuationToken? RehydrationToken { get; protected set; } + /// public override bool IsCompleted { get; protected set; } + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. public static async Task RehydrateAsync(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) { Argument.AssertNotNull(client, nameof(client)); @@ -53,6 +68,16 @@ public static async Task RehydrateAsync(FineTuningClient cl return new FineTuningOperation(client.Pipeline, client.Endpoint, token.JobId, status, response); } + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. public static FineTuningOperation Rehydrate(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) { Argument.AssertNotNull(client, nameof(client)); @@ -69,6 +94,7 @@ public static FineTuningOperation Rehydrate(FineTuningClient client, Continuatio return new FineTuningOperation(client.Pipeline, client.Endpoint, token.JobId, status, response); } + /// public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) { _pollingInterval ??= new(); @@ -85,6 +111,13 @@ public override async Task WaitForCompletionAsync(CancellationToken cancellation } } + /// + /// Waits for the operation to complete processing on the service. + /// + /// The time to wait between sending requests + /// for status updates from the service. + /// A token that can be used to cancel this + /// method call. public async Task WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken = default) { _pollingInterval = new(pollingInterval); @@ -92,6 +125,7 @@ public async Task WaitForCompletionAsync(TimeSpan pollingInterval, CancellationT await WaitForCompletionAsync(cancellationToken).ConfigureAwait(false); } + /// public override void WaitForCompletion(CancellationToken cancellationToken = default) { _pollingInterval ??= new(); @@ -108,6 +142,13 @@ public override void WaitForCompletion(CancellationToken cancellationToken = def } } + /// + /// Waits for the operation to complete processing on the service. + /// + /// The time to wait between sending requests + /// for status updates from the service. + /// A token that can be used to cancel this + /// method call. public void WaitForCompletion(TimeSpan pollingInterval, CancellationToken cancellationToken = default) { _pollingInterval = new(pollingInterval); diff --git a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs index a6eb2db4..95158c8a 100644 --- a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs +++ b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs @@ -3,7 +3,6 @@ using System.ClientModel.Primitives; using System.Collections.Generic; using System.ComponentModel; -using System.Text.Json; using System.Threading.Tasks; namespace OpenAI.VectorStores; diff --git a/src/Custom/VectorStores/VectorStoreFileBatchOperation.Protocol.cs b/src/Custom/VectorStores/VectorStoreFileBatchOperation.Protocol.cs index 859828da..89f48754 100644 --- a/src/Custom/VectorStores/VectorStoreFileBatchOperation.Protocol.cs +++ b/src/Custom/VectorStores/VectorStoreFileBatchOperation.Protocol.cs @@ -9,6 +9,9 @@ namespace OpenAI.VectorStores; +/// +/// Long-running operation for creating a vector store file batch. +/// public partial class VectorStoreFileBatchOperation : OperationResult { private readonly ClientPipeline _pipeline; @@ -19,8 +22,10 @@ public partial class VectorStoreFileBatchOperation : OperationResult private PollingInterval? _pollingInterval; + /// public override ContinuationToken? RehydrationToken { get; protected set; } + /// public override bool IsCompleted { get; protected set; } // Generated protocol methods diff --git a/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs b/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs index 5d06555c..b52c1cd1 100644 --- a/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs +++ b/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs @@ -8,6 +8,9 @@ namespace OpenAI.VectorStores; +/// +/// Long-running operation for creating a vector store file batch. +/// public partial class VectorStoreFileBatchOperation : OperationResult { internal VectorStoreFileBatchOperation( @@ -29,12 +32,36 @@ internal VectorStoreFileBatchOperation( RehydrationToken = new VectorStoreFileBatchOperationToken(VectorStoreId, BatchId); } + /// + /// The current value of the in progress. + /// public VectorStoreBatchFileJob? Value { get; private set; } + + /// + /// The current status of the in progress. + /// public VectorStoreBatchFileJobStatus? Status { get; private set; } + /// + /// The ID of the vector store corresponding to this batch file operation. + /// public string VectorStoreId { get => _vectorStoreId; } + + /// + /// The ID of the batch file job represented by this operation. + /// public string BatchId { get => _batchId; } + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. #pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. public static async Task RehydrateAsync(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) #pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -51,6 +78,16 @@ public static async Task RehydrateAsync(VectorSto return new VectorStoreFileBatchOperation(client.Pipeline, client.Endpoint, FromValue(job, response)); } + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. #pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. public static VectorStoreFileBatchOperation Rehydrate(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) #pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. @@ -67,6 +104,7 @@ public static VectorStoreFileBatchOperation Rehydrate(VectorStoreClient client, return new VectorStoreFileBatchOperation(client.Pipeline, client.Endpoint, FromValue(job, response)); } + /// public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) { _pollingInterval ??= new(); @@ -83,6 +121,13 @@ public override async Task WaitForCompletionAsync(CancellationToken cancellation } } + /// + /// Waits for the operation to complete processing on the service. + /// + /// The time to wait between sending requests + /// for status updates from the service. + /// A token that can be used to cancel this + /// method call. public async Task WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken = default) { _pollingInterval = new(pollingInterval); @@ -90,6 +135,7 @@ public async Task WaitForCompletionAsync(TimeSpan pollingInterval, CancellationT await WaitForCompletionAsync(cancellationToken).ConfigureAwait(false); } + /// public override void WaitForCompletion(CancellationToken cancellationToken = default) { _pollingInterval ??= new(); @@ -106,6 +152,13 @@ public override void WaitForCompletion(CancellationToken cancellationToken = def } } + /// + /// Waits for the operation to complete processing on the service. + /// + /// The time to wait between sending requests + /// for status updates from the service. + /// A token that can be used to cancel this + /// method call. public void WaitForCompletion(TimeSpan pollingInterval, CancellationToken cancellationToken = default) { _pollingInterval = new(pollingInterval); From d534f79538183ca97f276b00744a6e893020b009 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Tue, 6 Aug 2024 12:46:04 -0700 Subject: [PATCH 11/14] Add default value for cancellationToken in Rehydrate methods; add test for rehydration --- src/Custom/Batch/BatchOperation.Protocol.cs | 4 +- .../FineTuningOperation.Protocol.cs | 4 +- .../VectorStoreFileBatchOperation.cs | 4 +- tests/Assistants/VectorStoreTests.cs | 39 +++++++++++++++++++ 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/Custom/Batch/BatchOperation.Protocol.cs b/src/Custom/Batch/BatchOperation.Protocol.cs index 3a88a9c9..d1198765 100644 --- a/src/Custom/Batch/BatchOperation.Protocol.cs +++ b/src/Custom/Batch/BatchOperation.Protocol.cs @@ -54,7 +54,7 @@ internal BatchOperation( /// A token that can be used to cancel the /// request. /// The rehydrated operation. - public static async Task RehydrateAsync(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) + public static async Task RehydrateAsync(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) { Argument.AssertNotNull(client, nameof(client)); Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); @@ -80,7 +80,7 @@ public static async Task RehydrateAsync(BatchClient client, Cont /// A token that can be used to cancel the /// request. /// The rehydrated operation. - public static BatchOperation Rehydrate(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) + public static BatchOperation Rehydrate(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) { Argument.AssertNotNull(client, nameof(client)); Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); diff --git a/src/Custom/FineTuning/FineTuningOperation.Protocol.cs b/src/Custom/FineTuning/FineTuningOperation.Protocol.cs index 32f1843c..eb7b4826 100644 --- a/src/Custom/FineTuning/FineTuningOperation.Protocol.cs +++ b/src/Custom/FineTuning/FineTuningOperation.Protocol.cs @@ -52,7 +52,7 @@ internal FineTuningOperation( /// A token that can be used to cancel the /// request. /// The rehydrated operation. - public static async Task RehydrateAsync(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) + public static async Task RehydrateAsync(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) { Argument.AssertNotNull(client, nameof(client)); Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); @@ -78,7 +78,7 @@ public static async Task RehydrateAsync(FineTuningClient cl /// A token that can be used to cancel the /// request. /// The rehydrated operation. - public static FineTuningOperation Rehydrate(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) + public static FineTuningOperation Rehydrate(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) { Argument.AssertNotNull(client, nameof(client)); Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); diff --git a/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs b/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs index b52c1cd1..c90532a7 100644 --- a/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs +++ b/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs @@ -63,7 +63,7 @@ internal VectorStoreFileBatchOperation( /// request. /// The rehydrated operation. #pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - public static async Task RehydrateAsync(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) + public static async Task RehydrateAsync(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) #pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. { Argument.AssertNotNull(client, nameof(client)); @@ -89,7 +89,7 @@ public static async Task RehydrateAsync(VectorSto /// request. /// The rehydrated operation. #pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - public static VectorStoreFileBatchOperation Rehydrate(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken) + public static VectorStoreFileBatchOperation Rehydrate(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) #pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. { Argument.AssertNotNull(client, nameof(client)); diff --git a/tests/Assistants/VectorStoreTests.cs b/tests/Assistants/VectorStoreTests.cs index cc12ebe1..64073d77 100644 --- a/tests/Assistants/VectorStoreTests.cs +++ b/tests/Assistants/VectorStoreTests.cs @@ -297,6 +297,45 @@ public void CanUseBatchIngestion() } } + [Test] + public void CanRehydrateBatchFileJob() + { + VectorStoreClient client = GetTestClient(); + VectorStore vectorStore = client.CreateVectorStore(); + Validate(vectorStore); + + IReadOnlyList testFiles = GetNewTestFiles(5); + + VectorStoreFileBatchOperation batchOperation = client.CreateBatchFileJob(ReturnWhen.Started, vectorStore, testFiles); + Validate(batchOperation); + + // Simulate rehydration of the collection + BinaryData rehydrationBytes = batchOperation.RehydrationToken.ToBytes(); + ContinuationToken rehydrationToken = ContinuationToken.FromBytes(rehydrationBytes); + + VectorStoreFileBatchOperation rehydratedOperation = VectorStoreFileBatchOperation.Rehydrate(client, rehydrationToken); + Validate(rehydratedOperation); + + Assert.Multiple(() => + { + Assert.That(batchOperation.BatchId, Is.Not.Null); + Assert.That(batchOperation.VectorStoreId, Is.EqualTo(vectorStore.Id)); + Assert.That(batchOperation.Status, Is.EqualTo(VectorStoreBatchFileJobStatus.InProgress)); + + Assert.That(rehydratedOperation.BatchId, Is.EqualTo(batchOperation.BatchId)); + Assert.That(rehydratedOperation.VectorStoreId, Is.EqualTo(vectorStore.Id)); + Assert.That(rehydratedOperation.Status, Is.EqualTo(VectorStoreBatchFileJobStatus.InProgress)); + }); + + Task.WaitAll( + Task.Run(() => batchOperation.WaitForCompletion()), + Task.Run(() => rehydratedOperation.WaitForCompletion())); + + Assert.IsTrue(batchOperation.IsCompleted); + Assert.IsTrue(rehydratedOperation.IsCompleted); + Assert.AreEqual(batchOperation.Status, rehydratedOperation.Status); + } + public enum ChunkingStrategyKind { Auto, Static } [Test] From 7888d0e433699d21f6407ef7ad3f2d0b6b7299b4 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Tue, 6 Aug 2024 12:52:24 -0700 Subject: [PATCH 12/14] add missed refdocs --- .../VectorStoreClient.Convenience.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Custom/VectorStores/VectorStoreClient.Convenience.cs b/src/Custom/VectorStores/VectorStoreClient.Convenience.cs index cd0a9926..b7653e79 100644 --- a/src/Custom/VectorStores/VectorStoreClient.Convenience.cs +++ b/src/Custom/VectorStores/VectorStoreClient.Convenience.cs @@ -167,20 +167,30 @@ public virtual ClientResult RemoveFileFromStore(VectorStore vectorStore, O /// /// Begins a batch job to associate multiple jobs with a vector store, beginning the ingestion process. /// - /// TODO + /// if the + /// method should return when the service has finished running the + /// operation, or if it should return + /// after the operation has been created but may not have completed + /// processing. /// The vector store to associate files with. /// The files to associate with the vector store. - /// A instance representing the batch operation. + /// A that can be used to wait for + /// the operation to complete, get information about the batch file job, or cancel the operation. public virtual Task CreateBatchFileJobAsync(ReturnWhen returnWhen, VectorStore vectorStore, IEnumerable files) => CreateBatchFileJobAsync(returnWhen, vectorStore?.Id, files?.Select(file => file.Id)); /// /// Begins a batch job to associate multiple jobs with a vector store, beginning the ingestion process. /// - /// TODO + /// if the + /// method should return when the service has finished running the + /// operation, or if it should return + /// after the operation has been created but may not have completed + /// processing. /// The vector store to associate files with. /// The files to associate with the vector store. - /// A instance representing the batch operation. + /// A that can be used to wait for + /// the operation to complete, get information about the batch file job, or cancel the operation. public virtual VectorStoreFileBatchOperation CreateBatchFileJob(ReturnWhen returnWhen, VectorStore vectorStore, IEnumerable files) => CreateBatchFileJob(returnWhen, vectorStore?.Id, files?.Select(file => file.Id)); } From 162a9a690cd652f954a6c6deab14411ad793fcce Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Fri, 9 Aug 2024 09:21:53 -0700 Subject: [PATCH 13/14] updates --- api/OpenAI.netstandard2.0.cs | 176 +++++--- .../Assistants/AssistantClient.Protocol.cs | 16 +- src/Custom/Assistants/AssistantClient.cs | 177 ++------ .../Pagination/AssistantsPageEnumerator.cs | 2 + .../Pagination/MessagesPageEnumerator.cs | 2 + .../Pagination/RunStepsPageEnumerator.cs | 2 + .../Internal/Pagination/RunsPageEnumerator.cs | 2 + src/Custom/Batch/BatchClient.Protocol.cs | 46 +-- src/Custom/Batch/BatchClient.cs | 4 + .../Batch/CreateBatchOperation.Protocol.cs | 255 ++++++++++++ src/Custom/Batch/CreateBatchOperationToken.cs | 90 +++++ .../FineTuning/CreateJobOperation.Protocol.cs | 380 ++++++++++++++++++ .../FineTuning/CreateJobOperationToken.cs | 91 +++++ .../FineTuning/FineTuningClient.Protocol.cs | 50 +-- .../AddFileToVectorStoreOperation.Protocol.cs | 73 ++++ .../AddFileToVectorStoreOperation.cs | 194 +++++++++ .../AddFileToVectorStoreOperationToken.cs | 101 +++++ .../CreateBatchFileJobOperation.Protocol.cs | 227 +++++++++++ .../CreateBatchFileJobOperation.cs | 335 +++++++++++++++ .../CreateBatchFileJobOperationToken.cs | 101 +++++ .../CreateVectorStoreOperation.Protocol.cs | 70 ++++ .../CreateVectorStoreOperation.cs | 184 +++++++++ .../CreateVectorStoreOperationToken.cs | 90 +++++ .../VectorStoreFileBatchesPageEnumerator.cs | 12 +- .../VectorStoreFilesPageEnumerator.cs | 2 + .../Pagination/VectorStoresPageEnumerator.cs | 4 +- .../VectorStoreClient.Convenience.cs | 56 +-- .../VectorStoreClient.Protocol.cs | 111 +++-- src/Custom/VectorStores/VectorStoreClient.cs | 218 ++++------ src/Generated/BatchClient.cs | 17 + src/Generated/FineTuningClient.cs | 67 +++ src/Generated/VectorStoreClient.cs | 74 ++++ tests/Assistants/VectorStoreTests.cs | 83 ++-- tests/Batch/BatchTests.cs | 86 +++- tests/FineTuning/FineTuningTests.cs | 9 +- 35 files changed, 2870 insertions(+), 537 deletions(-) create mode 100644 src/Custom/Batch/CreateBatchOperation.Protocol.cs create mode 100644 src/Custom/Batch/CreateBatchOperationToken.cs create mode 100644 src/Custom/FineTuning/CreateJobOperation.Protocol.cs create mode 100644 src/Custom/FineTuning/CreateJobOperationToken.cs create mode 100644 src/Custom/VectorStores/AddFileToVectorStoreOperation.Protocol.cs create mode 100644 src/Custom/VectorStores/AddFileToVectorStoreOperation.cs create mode 100644 src/Custom/VectorStores/AddFileToVectorStoreOperationToken.cs create mode 100644 src/Custom/VectorStores/CreateBatchFileJobOperation.Protocol.cs create mode 100644 src/Custom/VectorStores/CreateBatchFileJobOperation.cs create mode 100644 src/Custom/VectorStores/CreateBatchFileJobOperationToken.cs create mode 100644 src/Custom/VectorStores/CreateVectorStoreOperation.Protocol.cs create mode 100644 src/Custom/VectorStores/CreateVectorStoreOperation.cs create mode 100644 src/Custom/VectorStores/CreateVectorStoreOperationToken.cs diff --git a/api/OpenAI.netstandard2.0.cs b/api/OpenAI.netstandard2.0.cs index 24d7c45a..33e6bbf3 100644 --- a/api/OpenAI.netstandard2.0.cs +++ b/api/OpenAI.netstandard2.0.cs @@ -1146,15 +1146,24 @@ public class BatchClient { public BatchClient(ApiKeyCredential credential, OpenAIClientOptions options = null); protected internal BatchClient(ClientPipeline pipeline, Uri endpoint, OpenAIClientOptions options); public virtual ClientPipeline Pipeline { get; } - public virtual ClientResult CancelBatch(string batchId, RequestOptions options); - public virtual Task CancelBatchAsync(string batchId, RequestOptions options); - public virtual ClientResult CreateBatch(BinaryContent content, RequestOptions options = null); - public virtual Task CreateBatchAsync(BinaryContent content, RequestOptions options = null); - public virtual ClientResult GetBatch(string batchId, RequestOptions options); - public virtual Task GetBatchAsync(string batchId, RequestOptions options); + public virtual CreateBatchOperation CreateBatch(bool waitUntilCompleted, BinaryContent content, RequestOptions options = null); + public virtual Task CreateBatchAsync(bool waitUntilCompleted, BinaryContent content, RequestOptions options = null); public virtual ClientResult GetBatches(string after, int? limit, RequestOptions options); public virtual Task GetBatchesAsync(string after, int? limit, RequestOptions options); } + public class CreateBatchOperation : OperationResult { + public string BatchId { get; } + public override bool IsCompleted { get; protected set; } + public override ContinuationToken? RehydrationToken { get; protected set; } + public virtual ClientResult CancelBatch(RequestOptions? options); + public virtual Task CancelBatchAsync(RequestOptions? options); + public virtual ClientResult GetBatch(RequestOptions? options); + public virtual Task GetBatchAsync(RequestOptions? options); + public static CreateBatchOperation Rehydrate(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default); + public static Task RehydrateAsync(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default); + public override void WaitForCompletion(CancellationToken cancellationToken = default); + public override Task WaitForCompletionAsync(CancellationToken cancellationToken = default); + } } namespace OpenAI.Chat { public class AssistantChatMessage : ChatMessage, IJsonModel, IPersistableModel { @@ -1719,22 +1728,31 @@ public class OpenAIFileInfoCollection : ObjectModel.ReadOnlyCollection CancelJobAsync(RequestOptions? options); + public virtual ClientResult GetJob(RequestOptions? options); + public virtual Task GetJobAsync(RequestOptions? options); + public virtual ClientResult GetJobCheckpoints(string after, int? limit, RequestOptions? options); + public virtual Task GetJobCheckpointsAsync(string after, int? limit, RequestOptions? options); + public virtual ClientResult GetJobEvents(string after, int? limit, RequestOptions? options); + public virtual Task GetJobEventsAsync(string after, int? limit, RequestOptions? options); + public static CreateJobOperation Rehydrate(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default); + public static Task RehydrateAsync(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default); + public override void WaitForCompletion(CancellationToken cancellationToken = default); + public override Task WaitForCompletionAsync(CancellationToken cancellationToken = default); + } public class FineTuningClient { protected FineTuningClient(); public FineTuningClient(OpenAIClientOptions options = null); public FineTuningClient(ApiKeyCredential credential, OpenAIClientOptions options = null); protected internal FineTuningClient(ClientPipeline pipeline, Uri endpoint, OpenAIClientOptions options); public virtual ClientPipeline Pipeline { get; } - public virtual ClientResult CancelJob(string jobId, RequestOptions options); - public virtual Task CancelJobAsync(string jobId, RequestOptions options); - public virtual ClientResult CreateJob(BinaryContent content, RequestOptions options = null); - public virtual Task CreateJobAsync(BinaryContent content, RequestOptions options = null); - public virtual ClientResult GetJob(string jobId, RequestOptions options); - public virtual Task GetJobAsync(string jobId, RequestOptions options); - public virtual ClientResult GetJobCheckpoints(string fineTuningJobId, string after, int? limit, RequestOptions options); - public virtual Task GetJobCheckpointsAsync(string fineTuningJobId, string after, int? limit, RequestOptions options); - public virtual ClientResult GetJobEvents(string jobId, string after, int? limit, RequestOptions options); - public virtual Task GetJobEventsAsync(string jobId, string after, int? limit, RequestOptions options); + public virtual CreateJobOperation CreateJob(bool waitUntilCompleted, BinaryContent content, RequestOptions options = null); + public virtual Task CreateJobAsync(bool waitUntilCompleted, BinaryContent content, RequestOptions options = null); public virtual ClientResult GetJobs(string after, int? limit, RequestOptions options); public virtual Task GetJobsAsync(string after, int? limit, RequestOptions options); } @@ -1986,6 +2004,75 @@ public class ModerationResult : IJsonModel, IPersistableModel< } } namespace OpenAI.VectorStores { + public class AddFileToVectorStoreOperation : OperationResult { + public AddFileToVectorStoreOperation(ClientPipeline pipeline, Uri endpoint, ClientResult result) : base(default!); + public string FileId { get; } + public override bool IsCompleted { get; protected set; } + public override ContinuationToken? RehydrationToken { get; protected set; } + public VectorStoreFileAssociationStatus? Status { get; } + public VectorStoreFileAssociation? Value { get; } + public string VectorStoreId { get; } + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult GetFileAssociation(RequestOptions? options); + public virtual ClientResult GetFileAssociation(CancellationToken cancellationToken = default); + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual Task GetFileAssociationAsync(RequestOptions? options); + public virtual Task> GetFileAssociationAsync(CancellationToken cancellationToken = default); + public static AddFileToVectorStoreOperation Rehydrate(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default); + public static Task RehydrateAsync(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default); + public override void WaitForCompletion(CancellationToken cancellationToken = default); + public override Task WaitForCompletionAsync(CancellationToken cancellationToken = default); + } + public class CreateBatchFileJobOperation : OperationResult { + public string BatchId { get; } + public override bool IsCompleted { get; protected set; } + public override ContinuationToken? RehydrationToken { get; protected set; } + public VectorStoreBatchFileJobStatus? Status { get; } + public VectorStoreBatchFileJob? Value { get; } + public string VectorStoreId { get; } + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult CancelFileBatch(RequestOptions? options); + public virtual ClientResult CancelFileBatch(CancellationToken cancellationToken = default); + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual Task CancelFileBatchAsync(RequestOptions? options); + public virtual Task> CancelFileBatchAsync(CancellationToken cancellationToken = default); + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult GetFileBatch(RequestOptions? options); + public virtual ClientResult GetFileBatch(CancellationToken cancellationToken = default); + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual Task GetFileBatchAsync(RequestOptions? options); + public virtual Task> GetFileBatchAsync(CancellationToken cancellationToken = default); + public virtual PageCollection GetFilesInBatch(VectorStoreFileAssociationCollectionOptions? options = null, CancellationToken cancellationToken = default); + public virtual PageCollection GetFilesInBatch(ContinuationToken firstPageToken, CancellationToken cancellationToken = default); + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual IEnumerable GetFilesInBatch(int? limit, string? order, string? after, string? before, string? filter, RequestOptions? options); + public virtual AsyncPageCollection GetFilesInBatchAsync(VectorStoreFileAssociationCollectionOptions? options = null, CancellationToken cancellationToken = default); + public virtual AsyncPageCollection GetFilesInBatchAsync(ContinuationToken firstPageToken, CancellationToken cancellationToken = default); + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual IAsyncEnumerable GetFilesInBatchAsync(int? limit, string? order, string? after, string? before, string? filter, RequestOptions? options); + public static CreateBatchFileJobOperation Rehydrate(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default); + public static Task RehydrateAsync(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default); + public override void WaitForCompletion(CancellationToken cancellationToken = default); + public override Task WaitForCompletionAsync(CancellationToken cancellationToken = default); + } + public class CreateVectorStoreOperation : OperationResult { + public CreateVectorStoreOperation(ClientPipeline pipeline, Uri endpoint, ClientResult result) : base(default!); + public override bool IsCompleted { get; protected set; } + public override ContinuationToken? RehydrationToken { get; protected set; } + public VectorStoreStatus? Status { get; } + public VectorStore? Value { get; } + public string VectorStoreId { get; } + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult GetVectorStore(RequestOptions? options); + public virtual ClientResult GetVectorStore(CancellationToken cancellationToken = default); + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual Task GetVectorStoreAsync(RequestOptions? options); + public virtual Task> GetVectorStoreAsync(CancellationToken cancellationToken = default); + public static CreateVectorStoreOperation Rehydrate(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default); + public static Task RehydrateAsync(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default); + public override void WaitForCompletion(CancellationToken cancellationToken = default); + public override Task WaitForCompletionAsync(CancellationToken cancellationToken = default); + } public abstract class FileChunkingStrategy : IJsonModel, IPersistableModel { public static FileChunkingStrategy Auto { get; } public static FileChunkingStrategy Unknown { get; } @@ -2059,34 +2146,29 @@ public class VectorStoreClient { public VectorStoreClient(ApiKeyCredential credential, OpenAIClientOptions options = null); protected internal VectorStoreClient(ClientPipeline pipeline, Uri endpoint, OpenAIClientOptions options); public virtual ClientPipeline Pipeline { get; } - public virtual ClientResult AddFileToVectorStore(VectorStore vectorStore, OpenAIFileInfo file); + public virtual AddFileToVectorStoreOperation AddFileToVectorStore(bool waitUntilCompleted, VectorStore vectorStore, OpenAIFileInfo file); [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult AddFileToVectorStore(string vectorStoreId, BinaryContent content, RequestOptions options = null); - public virtual ClientResult AddFileToVectorStore(string vectorStoreId, string fileId, CancellationToken cancellationToken = default); - public virtual Task> AddFileToVectorStoreAsync(VectorStore vectorStore, OpenAIFileInfo file); + public virtual AddFileToVectorStoreOperation AddFileToVectorStore(bool waitUntilCompleted, string vectorStoreId, BinaryContent content, RequestOptions options = null); + public virtual AddFileToVectorStoreOperation AddFileToVectorStore(bool waitUntilCompleted, string vectorStoreId, string fileId, CancellationToken cancellationToken = default); + public virtual Task AddFileToVectorStoreAsync(bool waitUntilCompleted, VectorStore vectorStore, OpenAIFileInfo file); [EditorBrowsable(EditorBrowsableState.Never)] - public virtual Task AddFileToVectorStoreAsync(string vectorStoreId, BinaryContent content, RequestOptions options = null); - public virtual Task> AddFileToVectorStoreAsync(string vectorStoreId, string fileId, CancellationToken cancellationToken = default); - public virtual ClientResult CancelBatchFileJob(VectorStoreBatchFileJob batchJob); + public virtual Task AddFileToVectorStoreAsync(bool waitUntilCompleted, string vectorStoreId, BinaryContent content, RequestOptions options = null); + public virtual Task AddFileToVectorStoreAsync(bool waitUntilCompleted, string vectorStoreId, string fileId, CancellationToken cancellationToken = default); + public virtual CreateBatchFileJobOperation CreateBatchFileJob(bool waitUntilCompleted, VectorStore vectorStore, IEnumerable files); [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult CancelBatchFileJob(string vectorStoreId, string batchId, RequestOptions options); - public virtual ClientResult CancelBatchFileJob(string vectorStoreId, string batchJobId, CancellationToken cancellationToken = default); - public virtual Task> CancelBatchFileJobAsync(VectorStoreBatchFileJob batchJob); + public virtual CreateBatchFileJobOperation CreateBatchFileJob(bool waitUntilCompleted, string vectorStoreId, BinaryContent content, RequestOptions options = null); + public virtual CreateBatchFileJobOperation CreateBatchFileJob(bool waitUntilCompleted, string vectorStoreId, IEnumerable fileIds, CancellationToken cancellationToken = default); + public virtual Task CreateBatchFileJobAsync(bool waitUntilCompleted, VectorStore vectorStore, IEnumerable files); [EditorBrowsable(EditorBrowsableState.Never)] - public virtual Task CancelBatchFileJobAsync(string vectorStoreId, string batchId, RequestOptions options); - public virtual Task> CancelBatchFileJobAsync(string vectorStoreId, string batchJobId, CancellationToken cancellationToken = default); - public virtual ClientResult CreateBatchFileJob(VectorStore vectorStore, IEnumerable files); - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult CreateBatchFileJob(string vectorStoreId, BinaryContent content, RequestOptions options = null); - public virtual ClientResult CreateBatchFileJob(string vectorStoreId, IEnumerable fileIds, CancellationToken cancellationToken = default); - public virtual Task> CreateBatchFileJobAsync(VectorStore vectorStore, IEnumerable files); - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual Task CreateBatchFileJobAsync(string vectorStoreId, BinaryContent content, RequestOptions options = null); - public virtual Task> CreateBatchFileJobAsync(string vectorStoreId, IEnumerable fileIds, CancellationToken cancellationToken = default); - public virtual ClientResult CreateVectorStore(VectorStoreCreationOptions vectorStore = null, CancellationToken cancellationToken = default); + public virtual Task CreateBatchFileJobAsync(bool waitUntilCompleted, string vectorStoreId, BinaryContent content, RequestOptions options = null); + public virtual Task CreateBatchFileJobAsync(bool waitUntilCompleted, string vectorStoreId, IEnumerable fileIds, CancellationToken cancellationToken = default); + public virtual CreateVectorStoreOperation CreateVectorStore(bool waitUntilCompleted, VectorStoreCreationOptions vectorStore = null, CancellationToken cancellationToken = default); [EditorBrowsable(EditorBrowsableState.Never)] + public virtual CreateVectorStoreOperation CreateVectorStore(bool waitUntilCompleted, BinaryContent content, RequestOptions options = null); public virtual ClientResult CreateVectorStore(BinaryContent content, RequestOptions options = null); - public virtual Task> CreateVectorStoreAsync(VectorStoreCreationOptions vectorStore = null, CancellationToken cancellationToken = default); + public virtual Task CreateVectorStoreAsync(bool waitUntilCompleted, VectorStoreCreationOptions vectorStore = null, CancellationToken cancellationToken = default); + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual Task CreateVectorStoreAsync(bool waitUntilCompleted, BinaryContent content, RequestOptions options = null); public virtual Task CreateVectorStoreAsync(BinaryContent content, RequestOptions options = null); public virtual ClientResult DeleteVectorStore(VectorStore vectorStore); [EditorBrowsable(EditorBrowsableState.Never)] @@ -2096,14 +2178,6 @@ public class VectorStoreClient { [EditorBrowsable(EditorBrowsableState.Never)] public virtual Task DeleteVectorStoreAsync(string vectorStoreId, RequestOptions options); public virtual Task> DeleteVectorStoreAsync(string vectorStoreId, CancellationToken cancellationToken = default); - public virtual ClientResult GetBatchFileJob(VectorStoreBatchFileJob batchJob); - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult GetBatchFileJob(string vectorStoreId, string batchId, RequestOptions options); - public virtual ClientResult GetBatchFileJob(string vectorStoreId, string batchJobId, CancellationToken cancellationToken = default); - public virtual Task> GetBatchFileJobAsync(VectorStoreBatchFileJob batchJob); - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual Task GetBatchFileJobAsync(string vectorStoreId, string batchId, RequestOptions options); - public virtual Task> GetBatchFileJobAsync(string vectorStoreId, string batchJobId, CancellationToken cancellationToken = default); public virtual ClientResult GetFileAssociation(VectorStore vectorStore, OpenAIFileInfo file); [EditorBrowsable(EditorBrowsableState.Never)] public virtual ClientResult GetFileAssociation(string vectorStoreId, string fileId, RequestOptions options); @@ -2113,25 +2187,15 @@ public class VectorStoreClient { public virtual Task GetFileAssociationAsync(string vectorStoreId, string fileId, RequestOptions options); public virtual Task> GetFileAssociationAsync(string vectorStoreId, string fileId, CancellationToken cancellationToken = default); public virtual PageCollection GetFileAssociations(VectorStore vectorStore, VectorStoreFileAssociationCollectionOptions options = null); - public virtual PageCollection GetFileAssociations(VectorStoreBatchFileJob batchJob, VectorStoreFileAssociationCollectionOptions options = null); public virtual PageCollection GetFileAssociations(ContinuationToken firstPageToken, CancellationToken cancellationToken = default); public virtual PageCollection GetFileAssociations(string vectorStoreId, VectorStoreFileAssociationCollectionOptions options = null, CancellationToken cancellationToken = default); [EditorBrowsable(EditorBrowsableState.Never)] public virtual IEnumerable GetFileAssociations(string vectorStoreId, int? limit, string order, string after, string before, string filter, RequestOptions options); - public virtual PageCollection GetFileAssociations(string vectorStoreId, string batchJobId, VectorStoreFileAssociationCollectionOptions options = null, CancellationToken cancellationToken = default); - public virtual PageCollection GetFileAssociations(string vectorStoreId, string batchJobId, ContinuationToken firstPageToken, CancellationToken cancellationToken = default); - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual IEnumerable GetFileAssociations(string vectorStoreId, string batchId, int? limit, string order, string after, string before, string filter, RequestOptions options); public virtual AsyncPageCollection GetFileAssociationsAsync(VectorStore vectorStore, VectorStoreFileAssociationCollectionOptions options = null); - public virtual AsyncPageCollection GetFileAssociationsAsync(VectorStoreBatchFileJob batchJob, VectorStoreFileAssociationCollectionOptions options = null); public virtual AsyncPageCollection GetFileAssociationsAsync(ContinuationToken firstPageToken, CancellationToken cancellationToken = default); public virtual AsyncPageCollection GetFileAssociationsAsync(string vectorStoreId, VectorStoreFileAssociationCollectionOptions options = null, CancellationToken cancellationToken = default); [EditorBrowsable(EditorBrowsableState.Never)] public virtual IAsyncEnumerable GetFileAssociationsAsync(string vectorStoreId, int? limit, string order, string after, string before, string filter, RequestOptions options); - public virtual AsyncPageCollection GetFileAssociationsAsync(string vectorStoreId, string batchJobId, VectorStoreFileAssociationCollectionOptions options = null, CancellationToken cancellationToken = default); - public virtual AsyncPageCollection GetFileAssociationsAsync(string vectorStoreId, string batchJobId, ContinuationToken firstPageToken, CancellationToken cancellationToken = default); - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual IAsyncEnumerable GetFileAssociationsAsync(string vectorStoreId, string batchId, int? limit, string order, string after, string before, string filter, RequestOptions options); public virtual ClientResult GetVectorStore(VectorStore vectorStore); [EditorBrowsable(EditorBrowsableState.Never)] public virtual ClientResult GetVectorStore(string vectorStoreId, RequestOptions options); diff --git a/src/Custom/Assistants/AssistantClient.Protocol.cs b/src/Custom/Assistants/AssistantClient.Protocol.cs index d96ee961..dace80d8 100644 --- a/src/Custom/Assistants/AssistantClient.Protocol.cs +++ b/src/Custom/Assistants/AssistantClient.Protocol.cs @@ -70,7 +70,7 @@ public virtual ClientResult CreateAssistant(BinaryContent content, RequestOption [EditorBrowsable(EditorBrowsableState.Never)] public virtual IAsyncEnumerable GetAssistantsAsync(int? limit, string order, string after, string before, RequestOptions options) { - AssistantsPageEnumerator enumerator = new AssistantsPageEnumerator(_pipeline, _endpoint, limit, order, after, before, options); + AssistantsPageEnumerator enumerator = new(_pipeline, _endpoint, limit, order, after, before, options); return PageCollectionHelpers.CreateAsync(enumerator); } @@ -101,7 +101,7 @@ public virtual IAsyncEnumerable GetAssistantsAsync(int? limit, str [EditorBrowsable(EditorBrowsableState.Never)] public virtual IEnumerable GetAssistants(int? limit, string order, string after, string before, RequestOptions options) { - AssistantsPageEnumerator enumerator = new AssistantsPageEnumerator(_pipeline, _endpoint, limit, order, after, before, options); + AssistantsPageEnumerator enumerator = new(_pipeline, _endpoint, limit, order, after, before, options); return PageCollectionHelpers.Create(enumerator); } @@ -259,7 +259,7 @@ public virtual IAsyncEnumerable GetMessagesAsync(string threadId, { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - MessagesPageEnumerator enumerator = new MessagesPageEnumerator(_pipeline, _endpoint, threadId, limit, order, after, before, options); + MessagesPageEnumerator enumerator = new(_pipeline, _endpoint, threadId, limit, order, after, before, options); return PageCollectionHelpers.CreateAsync(enumerator); } @@ -295,7 +295,7 @@ public virtual IEnumerable GetMessages(string threadId, int? limit { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - MessagesPageEnumerator enumerator = new MessagesPageEnumerator(_pipeline, _endpoint, threadId, limit, order, after, before, options); + MessagesPageEnumerator enumerator = new(_pipeline, _endpoint, threadId, limit, order, after, before, options); return PageCollectionHelpers.Create(enumerator); } @@ -381,7 +381,7 @@ public virtual IAsyncEnumerable GetRunsAsync(string threadId, int? { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - RunsPageEnumerator enumerator = new RunsPageEnumerator(_pipeline, _endpoint, threadId, limit, order, after, before, options); + RunsPageEnumerator enumerator = new(_pipeline, _endpoint, threadId, limit, order, after, before, options); return PageCollectionHelpers.CreateAsync(enumerator); } @@ -417,7 +417,7 @@ public virtual IEnumerable GetRuns(string threadId, int? limit, st { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - RunsPageEnumerator enumerator = new RunsPageEnumerator(_pipeline, _endpoint, threadId, limit, order, after, before, options); + RunsPageEnumerator enumerator = new(_pipeline, _endpoint, threadId, limit, order, after, before, options); return PageCollectionHelpers.Create(enumerator); } @@ -495,7 +495,7 @@ public virtual IAsyncEnumerable GetRunStepsAsync(string threadId, Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - RunStepsPageEnumerator enumerator = new RunStepsPageEnumerator(_pipeline, _endpoint, threadId, runId, limit, order, after, before, options); + RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, threadId, runId, limit, order, after, before, options); return PageCollectionHelpers.CreateAsync(enumerator); } @@ -533,7 +533,7 @@ public virtual IEnumerable GetRunSteps(string threadId, string run Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - RunStepsPageEnumerator enumerator = new RunStepsPageEnumerator(_pipeline, _endpoint, threadId, runId, limit, order, after, before, options); + RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, threadId, runId, limit, order, after, before, options); return PageCollectionHelpers.Create(enumerator); } diff --git a/src/Custom/Assistants/AssistantClient.cs b/src/Custom/Assistants/AssistantClient.cs index 611ef7ed..3ca8be2f 100644 --- a/src/Custom/Assistants/AssistantClient.cs +++ b/src/Custom/Assistants/AssistantClient.cs @@ -118,14 +118,8 @@ public virtual AsyncPageCollection GetAssistantsAsync( AssistantCollectionOptions options = default, CancellationToken cancellationToken = default) { - AssistantsPageEnumerator enumerator = new(_pipeline, _endpoint, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); + return GetAssistantsAsync(options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, cancellationToken.ToRequestOptions()) + as AsyncPageCollection; } /// @@ -144,14 +138,8 @@ public virtual AsyncPageCollection GetAssistantsAsync( Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); AssistantsPageToken pageToken = AssistantsPageToken.FromToken(firstPageToken); - AssistantsPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); + return GetAssistantsAsync(pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken.Before, cancellationToken.ToRequestOptions()) + as AsyncPageCollection; } /// @@ -167,14 +155,8 @@ public virtual PageCollection GetAssistants( AssistantCollectionOptions options = default, CancellationToken cancellationToken = default) { - AssistantsPageEnumerator enumerator = new(_pipeline, _endpoint, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); + return GetAssistants(options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, cancellationToken.ToRequestOptions()) + as PageCollection; } /// @@ -193,14 +175,8 @@ public virtual PageCollection GetAssistants( Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); AssistantsPageToken pageToken = AssistantsPageToken.FromToken(firstPageToken); - AssistantsPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); + return GetAssistants(pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken.Before, cancellationToken.ToRequestOptions()) + as PageCollection; } /// @@ -486,15 +462,8 @@ public virtual AsyncPageCollection GetMessagesAsync( { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - MessagesPageEnumerator enumerator = new(_pipeline, _endpoint, - threadId, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); + return GetMessagesAsync(threadId, options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, cancellationToken.ToRequestOptions()) + as AsyncPageCollection; } /// @@ -513,15 +482,8 @@ public virtual AsyncPageCollection GetMessagesAsync( Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); MessagesPageToken pageToken = MessagesPageToken.FromToken(firstPageToken); - MessagesPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.ThreadId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); + return GetMessagesAsync(pageToken?.ThreadId, pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken?.Before, cancellationToken.ToRequestOptions()) + as AsyncPageCollection; } /// @@ -541,15 +503,8 @@ public virtual PageCollection GetMessages( { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - MessagesPageEnumerator enumerator = new(_pipeline, _endpoint, - threadId, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); + return GetMessages(threadId, options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, cancellationToken.ToRequestOptions()) + as PageCollection; } /// @@ -568,15 +523,9 @@ public virtual PageCollection GetMessages( Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); MessagesPageToken pageToken = MessagesPageToken.FromToken(firstPageToken); - MessagesPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.ThreadId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); + return GetMessages(pageToken?.ThreadId, pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken?.Before, cancellationToken.ToRequestOptions()) + as PageCollection; + } /// @@ -888,15 +837,8 @@ public virtual AsyncPageCollection GetRunsAsync( { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - RunsPageEnumerator enumerator = new(_pipeline, _endpoint, - threadId, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); + return GetRunsAsync(threadId, options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, cancellationToken.ToRequestOptions()) + as AsyncPageCollection; } /// @@ -915,15 +857,8 @@ public virtual AsyncPageCollection GetRunsAsync( Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); RunsPageToken pageToken = RunsPageToken.FromToken(firstPageToken); - RunsPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.ThreadId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); + return GetRunsAsync(pageToken?.ThreadId, pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken?.Before, cancellationToken.ToRequestOptions()) + as AsyncPageCollection; } /// @@ -943,15 +878,8 @@ public virtual PageCollection GetRuns( { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - RunsPageEnumerator enumerator = new(_pipeline, _endpoint, - threadId, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); + return GetRuns(threadId, options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, cancellationToken.ToRequestOptions()) + as PageCollection; } /// @@ -970,15 +898,8 @@ public virtual PageCollection GetRuns( Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); RunsPageToken pageToken = RunsPageToken.FromToken(firstPageToken); - RunsPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.ThreadId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); + return GetRuns(pageToken?.ThreadId, pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken?.Before, cancellationToken.ToRequestOptions()) + as PageCollection; } /// @@ -1168,16 +1089,8 @@ public virtual AsyncPageCollection GetRunStepsAsync( Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, - threadId, - runId, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); + return GetRunStepsAsync(threadId, runId, options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, cancellationToken.ToRequestOptions()) + as AsyncPageCollection; } /// @@ -1196,16 +1109,8 @@ public virtual AsyncPageCollection GetRunStepsAsync( Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); RunStepsPageToken pageToken = RunStepsPageToken.FromToken(firstPageToken); - RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.ThreadId, - pageToken.RunId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); + return GetRunStepsAsync(pageToken?.ThreadId, pageToken?.RunId, pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken?.Before, cancellationToken.ToRequestOptions()) + as AsyncPageCollection; } /// @@ -1228,16 +1133,8 @@ public virtual PageCollection GetRunSteps( Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, - threadId, - runId, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); + return GetRunSteps(threadId, runId, options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, cancellationToken.ToRequestOptions()) + as PageCollection; } /// @@ -1256,16 +1153,8 @@ public virtual PageCollection GetRunSteps( Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); RunStepsPageToken pageToken = RunStepsPageToken.FromToken(firstPageToken); - RunStepsPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.ThreadId, - pageToken.RunId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); + return GetRunSteps(pageToken?.ThreadId, pageToken?.RunId, pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken?.Before, cancellationToken.ToRequestOptions()) + as PageCollection; } /// diff --git a/src/Custom/Assistants/Internal/Pagination/AssistantsPageEnumerator.cs b/src/Custom/Assistants/Internal/Pagination/AssistantsPageEnumerator.cs index 634dd6b1..66019bbb 100644 --- a/src/Custom/Assistants/Internal/Pagination/AssistantsPageEnumerator.cs +++ b/src/Custom/Assistants/Internal/Pagination/AssistantsPageEnumerator.cs @@ -21,6 +21,8 @@ internal partial class AssistantsPageEnumerator : PageEnumerator private readonly string _before; private readonly RequestOptions _options; + public virtual ClientPipeline Pipeline => _pipeline; + public AssistantsPageEnumerator( ClientPipeline pipeline, Uri endpoint, diff --git a/src/Custom/Assistants/Internal/Pagination/MessagesPageEnumerator.cs b/src/Custom/Assistants/Internal/Pagination/MessagesPageEnumerator.cs index c8ee0603..53e09fec 100644 --- a/src/Custom/Assistants/Internal/Pagination/MessagesPageEnumerator.cs +++ b/src/Custom/Assistants/Internal/Pagination/MessagesPageEnumerator.cs @@ -22,6 +22,8 @@ internal partial class MessagesPageEnumerator : PageEnumerator private readonly string _before; private readonly RequestOptions _options; + public virtual ClientPipeline Pipeline => _pipeline; + public MessagesPageEnumerator( ClientPipeline pipeline, Uri endpoint, diff --git a/src/Custom/Assistants/Internal/Pagination/RunStepsPageEnumerator.cs b/src/Custom/Assistants/Internal/Pagination/RunStepsPageEnumerator.cs index d6d74d7d..b5992ce7 100644 --- a/src/Custom/Assistants/Internal/Pagination/RunStepsPageEnumerator.cs +++ b/src/Custom/Assistants/Internal/Pagination/RunStepsPageEnumerator.cs @@ -23,6 +23,8 @@ internal partial class RunStepsPageEnumerator : PageEnumerator private string? _after; + public virtual ClientPipeline Pipeline => _pipeline; + public RunStepsPageEnumerator( ClientPipeline pipeline, Uri endpoint, diff --git a/src/Custom/Assistants/Internal/Pagination/RunsPageEnumerator.cs b/src/Custom/Assistants/Internal/Pagination/RunsPageEnumerator.cs index 3a0b827d..f48ceb3c 100644 --- a/src/Custom/Assistants/Internal/Pagination/RunsPageEnumerator.cs +++ b/src/Custom/Assistants/Internal/Pagination/RunsPageEnumerator.cs @@ -22,6 +22,8 @@ internal partial class RunsPageEnumerator : PageEnumerator private readonly string _before; private readonly RequestOptions _options; + public virtual ClientPipeline Pipeline => _pipeline; + public RunsPageEnumerator( ClientPipeline pipeline, Uri endpoint, diff --git a/src/Custom/Batch/BatchClient.Protocol.cs b/src/Custom/Batch/BatchClient.Protocol.cs index ad67b013..78aacf24 100644 --- a/src/Custom/Batch/BatchClient.Protocol.cs +++ b/src/Custom/Batch/BatchClient.Protocol.cs @@ -11,18 +11,17 @@ public partial class BatchClient /// /// [Protocol Method] Creates and executes a batch from an uploaded file of requests /// - /// if the - /// method should return when the service has finished running the - /// operation, or if it should return - /// after the operation has been created but may not have completed - /// processing. + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// is null. /// Service returned a non-success status code. - /// A that can be used to wait for + /// A that can be used to wait for /// the operation to complete, or cancel the operation. - public virtual async Task CreateBatchAsync(ReturnWhen returnWhen, BinaryContent content, RequestOptions options = null) + public virtual async Task CreateBatchAsync(bool waitUntilCompleted, BinaryContent content, RequestOptions options = null) { Argument.AssertNotNull(content, nameof(content)); @@ -34,31 +33,24 @@ public virtual async Task CreateBatchAsync(ReturnWhen returnWhen string batchId = doc.RootElement.GetProperty("id"u8).GetString(); string status = doc.RootElement.GetProperty("status"u8).GetString(); - BatchOperation operation = new BatchOperation(_pipeline, _endpoint, batchId, status, response); - if (returnWhen == ReturnWhen.Started) - { - return operation; - } - - await operation.WaitForCompletionAsync(options?.CancellationToken ?? default).ConfigureAwait(false); - return operation; + CreateBatchOperation operation = new(_pipeline, _endpoint, batchId, status, response); + return await operation.WaitUntilAsync(waitUntilCompleted, options).ConfigureAwait(false); } /// /// [Protocol Method] Creates and executes a batch from an uploaded file of requests /// - /// if the - /// method should return when the service has finished running the - /// operation, or if it should return - /// after the operation has been created but may not have completed - /// processing. + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// is null. /// Service returned a non-success status code. - /// A that can be used to wait for + /// A that can be used to wait for /// the operation to complete, or cancel the operation. - public virtual BatchOperation CreateBatch(ReturnWhen returnWhen, BinaryContent content, RequestOptions options = null) + public virtual CreateBatchOperation CreateBatch(bool waitUntilCompleted, BinaryContent content, RequestOptions options = null) { Argument.AssertNotNull(content, nameof(content)); @@ -69,14 +61,8 @@ public virtual BatchOperation CreateBatch(ReturnWhen returnWhen, BinaryContent c string batchId = doc.RootElement.GetProperty("id"u8).GetString(); string status = doc.RootElement.GetProperty("status"u8).GetString(); - BatchOperation operation = new BatchOperation(_pipeline, _endpoint, batchId, status, response); - if (returnWhen == ReturnWhen.Started) - { - return operation; - } - - operation.WaitForCompletion(options?.CancellationToken ?? default); - return operation; + CreateBatchOperation operation = new(_pipeline, _endpoint, batchId, status, response); + return operation.WaitUntil(waitUntilCompleted, options); } /// diff --git a/src/Custom/Batch/BatchClient.cs b/src/Custom/Batch/BatchClient.cs index 6a00166e..484444de 100644 --- a/src/Custom/Batch/BatchClient.cs +++ b/src/Custom/Batch/BatchClient.cs @@ -9,12 +9,16 @@ namespace OpenAI.Batch; [CodeGenSuppress("BatchClient", typeof(ClientPipeline), typeof(ApiKeyCredential), typeof(Uri))] [CodeGenSuppress("CreateBatch", typeof(string), typeof(InternalCreateBatchRequestEndpoint), typeof(InternalBatchCompletionTimeframe), typeof(IDictionary))] [CodeGenSuppress("CreateBatchAsync", typeof(string), typeof(InternalCreateBatchRequestEndpoint), typeof(InternalBatchCompletionTimeframe), typeof(IDictionary))] +[CodeGenSuppress("CreateBatch", typeof(BinaryContent), typeof(RequestOptions))] +[CodeGenSuppress("CreateBatchAsync", typeof(BinaryContent), typeof(RequestOptions))] [CodeGenSuppress("RetrieveBatch", typeof(string))] [CodeGenSuppress("RetrieveBatchAsync", typeof(string))] [CodeGenSuppress("RetrieveBatch", typeof(string), typeof(RequestOptions))] [CodeGenSuppress("RetrieveBatchAsync", typeof(string), typeof(RequestOptions))] [CodeGenSuppress("CancelBatch", typeof(string))] [CodeGenSuppress("CancelBatchAsync", typeof(string))] +[CodeGenSuppress("CancelBatch", typeof(string), typeof(RequestOptions))] +[CodeGenSuppress("CancelBatchAsync", typeof(string), typeof(RequestOptions))] [CodeGenSuppress("GetBatches", typeof(string), typeof(int?))] [CodeGenSuppress("GetBatchesAsync", typeof(string), typeof(int?))] public partial class BatchClient diff --git a/src/Custom/Batch/CreateBatchOperation.Protocol.cs b/src/Custom/Batch/CreateBatchOperation.Protocol.cs new file mode 100644 index 00000000..4f237429 --- /dev/null +++ b/src/Custom/Batch/CreateBatchOperation.Protocol.cs @@ -0,0 +1,255 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.Batch; + +/// +/// A long-running operation for executing a batch from an uploaded file of +/// requests. +/// +public partial class CreateBatchOperation : OperationResult +{ + private readonly ClientPipeline _pipeline; + private readonly Uri _endpoint; + + private readonly string _batchId; + + private PollingInterval? _pollingInterval; + + internal CreateBatchOperation( + ClientPipeline pipeline, + Uri endpoint, + string batchId, + string status, + PipelineResponse response) + : base(response) + { + _pipeline = pipeline; + _endpoint = endpoint; + _batchId = batchId; + + IsCompleted = GetIsCompleted(status); + RehydrationToken = new CreateBatchOperationToken(batchId); + } + + public string BatchId => _batchId; + + /// + public override ContinuationToken? RehydrationToken { get; protected set; } + + /// + public override bool IsCompleted { get; protected set; } + + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. + /// or is null. + public static async Task RehydrateAsync(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + CreateBatchOperationToken token = CreateBatchOperationToken.FromToken(rehydrationToken); + + ClientResult result = await client.GetBatchAsync(token.BatchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string status = doc.RootElement.GetProperty("status"u8).GetString()!; + + return new CreateBatchOperation(client.Pipeline, client.Endpoint, token.BatchId, status, response); + } + + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. + /// or is null. + public static CreateBatchOperation Rehydrate(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + CreateBatchOperationToken token = CreateBatchOperationToken.FromToken(rehydrationToken); + + ClientResult result = client.GetBatch(token.BatchId, cancellationToken.ToRequestOptions()); + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string status = doc.RootElement.GetProperty("status"u8).GetString()!; + + return new CreateBatchOperation(client.Pipeline, client.Endpoint, token.BatchId, status, response); + } + + /// + public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) + { + _pollingInterval ??= new(); + + while (!IsCompleted) + { + PipelineResponse response = GetRawResponse(); + + await _pollingInterval.WaitAsync(response, cancellationToken); + + ClientResult result = await GetBatchAsync(cancellationToken.ToRequestOptions()).ConfigureAwait(false); + + ApplyUpdate(result); + } + } + + /// + public override void WaitForCompletion(CancellationToken cancellationToken = default) + { + _pollingInterval ??= new(); + + while (!IsCompleted) + { + PipelineResponse response = GetRawResponse(); + + _pollingInterval.Wait(response, cancellationToken); + + ClientResult result = GetBatch(cancellationToken.ToRequestOptions()); + + ApplyUpdate(result); + } + } + + internal async Task WaitUntilAsync(bool waitUntilCompleted, RequestOptions? options) + { + if (!waitUntilCompleted) return this; + await WaitForCompletionAsync(options?.CancellationToken ?? default).ConfigureAwait(false); + return this; + } + + internal CreateBatchOperation WaitUntil(bool waitUntilCompleted, RequestOptions? options) + { + if (!waitUntilCompleted) return this; + WaitForCompletion(options?.CancellationToken ?? default); + return this; + } + + private void ApplyUpdate(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string? status = doc.RootElement.GetProperty("status"u8).GetString(); + + IsCompleted = GetIsCompleted(status); + SetRawResponse(response); + } + + private static bool GetIsCompleted(string? status) + { + return status == InternalBatchStatus.Completed || + status == InternalBatchStatus.Cancelled || + status == InternalBatchStatus.Expired || + status == InternalBatchStatus.Failed; + } + + // Generated protocol methods + + /// + /// [Protocol Method] Retrieves a batch. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetBatchAsync(RequestOptions? options) + { + using PipelineMessage message = CreateRetrieveBatchRequest(_batchId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Retrieves a batch. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult GetBatch(RequestOptions? options) + { + using PipelineMessage message = CreateRetrieveBatchRequest(_batchId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Cancels an in-progress batch. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task CancelBatchAsync( RequestOptions? options) + { + using PipelineMessage message = CreateCancelBatchRequest(_batchId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Cancels an in-progress batch. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult CancelBatch(RequestOptions? options) + { + using PipelineMessage message = CreateCancelBatchRequest(_batchId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + internal PipelineMessage CreateRetrieveBatchRequest(string batchId, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/batches/", false); + uri.AppendPath(batchId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateCancelBatchRequest(string batchId, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "POST"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/batches/", false); + uri.AppendPath(batchId, true); + uri.AppendPath("/cancel", false); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); +} \ No newline at end of file diff --git a/src/Custom/Batch/CreateBatchOperationToken.cs b/src/Custom/Batch/CreateBatchOperationToken.cs new file mode 100644 index 00000000..78b0d61c --- /dev/null +++ b/src/Custom/Batch/CreateBatchOperationToken.cs @@ -0,0 +1,90 @@ +using System; +using System.ClientModel; +using System.Diagnostics; +using System.IO; +using System.Text.Json; + +#nullable enable + +namespace OpenAI.Batch; + +internal class CreateBatchOperationToken : ContinuationToken +{ + public CreateBatchOperationToken(string batchId) + { + BatchId = batchId; + } + + public string BatchId { get; } + + public override BinaryData ToBytes() + { + using MemoryStream stream = new(); + using Utf8JsonWriter writer = new(stream); + writer.WriteStartObject(); + + writer.WriteString("batchId", BatchId); + + writer.WriteEndObject(); + + writer.Flush(); + stream.Position = 0; + + return BinaryData.FromStream(stream); + } + + public static CreateBatchOperationToken FromToken(ContinuationToken continuationToken) + { + if (continuationToken is CreateBatchOperationToken token) + { + return token; + } + + BinaryData data = continuationToken.ToBytes(); + + if (data.ToMemory().Length == 0) + { + throw new ArgumentException("Failed to create CreateBatchOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + Utf8JsonReader reader = new(data); + + string batchId = null!; + + reader.Read(); + + Debug.Assert(reader.TokenType == JsonTokenType.StartObject); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); + + string propertyName = reader.GetString()!; + + switch (propertyName) + { + case "batchId": + reader.Read(); + Debug.Assert(reader.TokenType == JsonTokenType.String); + batchId = reader.GetString()!; + break; + + default: + throw new JsonException($"Unrecognized property '{propertyName}'."); + } + } + + if (batchId is null) + { + throw new ArgumentException("Failed to create CreateBatchOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + return new(batchId); + } +} + diff --git a/src/Custom/FineTuning/CreateJobOperation.Protocol.cs b/src/Custom/FineTuning/CreateJobOperation.Protocol.cs new file mode 100644 index 00000000..e9601dd0 --- /dev/null +++ b/src/Custom/FineTuning/CreateJobOperation.Protocol.cs @@ -0,0 +1,380 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.FineTuning; + +/// +/// A long-running operation for creating a new model from a given dataset. +/// +public partial class CreateJobOperation : OperationResult +{ + private readonly ClientPipeline _pipeline; + private readonly Uri _endpoint; + + private readonly string _jobId; + + private PollingInterval? _pollingInterval; + + internal CreateJobOperation( + ClientPipeline pipeline, + Uri endpoint, + string jobId, + string status, + PipelineResponse response) : base(response) + { + _pipeline = pipeline; + _endpoint = endpoint; + _jobId = jobId; + + IsCompleted = GetIsCompleted(status); + RehydrationToken = new CreateJobOperationToken(jobId); + } + + public string JobId => _jobId; + + /// + public override ContinuationToken? RehydrationToken { get; protected set; } + + /// + public override bool IsCompleted { get; protected set; } + + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. + /// or is null. + public static async Task RehydrateAsync(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + CreateJobOperationToken token = CreateJobOperationToken.FromToken(rehydrationToken); + + ClientResult result = await client.GetJobAsync(token.JobId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string status = doc.RootElement.GetProperty("status"u8).GetString()!; + + return new CreateJobOperation(client.Pipeline, client.Endpoint, token.JobId, status, response); + } + + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. + /// or is null. + public static CreateJobOperation Rehydrate(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + CreateJobOperationToken token = CreateJobOperationToken.FromToken(rehydrationToken); + + ClientResult result = client.GetJob(token.JobId, cancellationToken.ToRequestOptions()); + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string status = doc.RootElement.GetProperty("status"u8).GetString()!; + + return new CreateJobOperation(client.Pipeline, client.Endpoint, token.JobId, status, response); + } + + /// + public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) + { + _pollingInterval ??= new(); + + while (!IsCompleted) + { + PipelineResponse response = GetRawResponse(); + + await _pollingInterval.WaitAsync(response, cancellationToken); + + ClientResult result = await GetJobAsync(cancellationToken.ToRequestOptions()).ConfigureAwait(false); + + ApplyUpdate(result); + } + } + + /// + public override void WaitForCompletion(CancellationToken cancellationToken = default) + { + _pollingInterval ??= new(); + + while (!IsCompleted) + { + PipelineResponse response = GetRawResponse(); + + _pollingInterval.Wait(response, cancellationToken); + + ClientResult result = GetJob(cancellationToken.ToRequestOptions()); + + ApplyUpdate(result); + } + } + + internal async Task WaitUntilAsync(bool waitUntilCompleted, RequestOptions? options) + { + if (!waitUntilCompleted) return this; + await WaitForCompletionAsync(options?.CancellationToken ?? default).ConfigureAwait(false); + return this; + } + + internal CreateJobOperation WaitUntil(bool waitUntilCompleted, RequestOptions? options) + { + if (!waitUntilCompleted) return this; + WaitForCompletion(options?.CancellationToken ?? default); + return this; + } + + private void ApplyUpdate(ClientResult result) + { + PipelineResponse response = result.GetRawResponse(); + + using JsonDocument doc = JsonDocument.Parse(response.Content); + string? status = doc.RootElement.GetProperty("status"u8).GetString(); + + IsCompleted = GetIsCompleted(status); + SetRawResponse(response); + } + + private static bool GetIsCompleted(string? status) + { + return status == InternalFineTuningJobStatus.Succeeded || + status == InternalFineTuningJobStatus.Failed || + status == InternalFineTuningJobStatus.Cancelled; + } + + // Generated protocol methods + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Get info about a fine-tuning job. + /// + /// [Learn more about fine-tuning](/docs/guides/fine-tuning) + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetJobAsync(RequestOptions? options) + { + using PipelineMessage message = CreateRetrieveFineTuningJobRequest(_jobId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Get info about a fine-tuning job. + /// + /// [Learn more about fine-tuning](/docs/guides/fine-tuning) + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult GetJob(RequestOptions? options) + { + using PipelineMessage message = CreateRetrieveFineTuningJobRequest(_jobId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Immediately cancel a fine-tune job. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task CancelJobAsync(RequestOptions? options) + { + using PipelineMessage message = CreateCancelFineTuningJobRequest(_jobId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Immediately cancel a fine-tune job. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult CancelJob(RequestOptions? options) + { + using PipelineMessage message = CreateCancelFineTuningJobRequest(_jobId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Get status updates for a fine-tuning job. + /// + /// Identifier for the last event from the previous pagination request. + /// Number of events to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetJobEventsAsync(string after, int? limit, RequestOptions? options) + { + using PipelineMessage message = CreateGetFineTuningEventsRequest(_jobId, after, limit, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + // CUSTOM: + // - Renamed. + // - Edited doc comment. + /// + /// [Protocol Method] Get status updates for a fine-tuning job. + /// + /// Identifier for the last event from the previous pagination request. + /// Number of events to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult GetJobEvents(string after, int? limit, RequestOptions? options) + { + using PipelineMessage message = CreateGetFineTuningEventsRequest(_jobId, after, limit, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] List the checkpoints for a fine-tuning job. + /// + /// Identifier for the last checkpoint ID from the previous pagination request. + /// Number of checkpoints to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual async Task GetJobCheckpointsAsync(string after, int? limit, RequestOptions? options) + { + using PipelineMessage message = CreateGetFineTuningJobCheckpointsRequest(_jobId, after, limit, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] List the checkpoints for a fine-tuning job. + /// + /// Identifier for the last checkpoint ID from the previous pagination request. + /// Number of checkpoints to retrieve. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + public virtual ClientResult GetJobCheckpoints(string after, int? limit, RequestOptions? options) + { + using PipelineMessage message = CreateGetFineTuningJobCheckpointsRequest(_jobId, after, limit, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + internal PipelineMessage CreateRetrieveFineTuningJobRequest(string fineTuningJobId, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateCancelFineTuningJobRequest(string fineTuningJobId, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "POST"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + uri.AppendPath("/cancel", false); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateGetFineTuningJobCheckpointsRequest(string fineTuningJobId, string after, int? limit, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + uri.AppendPath("/checkpoints", false); + if (after != null) + { + uri.AppendQuery("after", after, true); + } + if (limit != null) + { + uri.AppendQuery("limit", limit.Value, true); + } + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateGetFineTuningEventsRequest(string fineTuningJobId, string after, int? limit, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + uri.AppendPath("/events", false); + if (after != null) + { + uri.AppendQuery("after", after, true); + } + if (limit != null) + { + uri.AppendQuery("limit", limit.Value, true); + } + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); +} diff --git a/src/Custom/FineTuning/CreateJobOperationToken.cs b/src/Custom/FineTuning/CreateJobOperationToken.cs new file mode 100644 index 00000000..9050970b --- /dev/null +++ b/src/Custom/FineTuning/CreateJobOperationToken.cs @@ -0,0 +1,91 @@ +using System; +using System.ClientModel; +using System.Diagnostics; +using System.IO; +using System.Text.Json; + +#nullable enable + +namespace OpenAI.FineTuning; + +internal class CreateJobOperationToken : ContinuationToken +{ + public CreateJobOperationToken(string jobId) + { + JobId = jobId; + } + + public string JobId { get; } + + public override BinaryData ToBytes() + { + using MemoryStream stream = new(); + using Utf8JsonWriter writer = new(stream); + + writer.WriteStartObject(); + + writer.WriteString("jobId", JobId); + + writer.WriteEndObject(); + + writer.Flush(); + stream.Position = 0; + + return BinaryData.FromStream(stream); + } + + public static CreateJobOperationToken FromToken(ContinuationToken continuationToken) + { + if (continuationToken is CreateJobOperationToken token) + { + return token; + } + + BinaryData data = continuationToken.ToBytes(); + + if (data.ToMemory().Length == 0) + { + throw new ArgumentException("Failed to create FineTuningJobOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + Utf8JsonReader reader = new(data); + + string jobId = null!; + + reader.Read(); + + Debug.Assert(reader.TokenType == JsonTokenType.StartObject); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); + + string propertyName = reader.GetString()!; + + switch (propertyName) + { + case "jobId": + reader.Read(); + Debug.Assert(reader.TokenType == JsonTokenType.String); + jobId = reader.GetString()!; + break; + + default: + throw new JsonException($"Unrecognized property '{propertyName}'."); + } + } + + if (jobId is null) + { + throw new ArgumentException("Failed to create FineTuningJobOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + return new(jobId); + } +} + diff --git a/src/Custom/FineTuning/FineTuningClient.Protocol.cs b/src/Custom/FineTuning/FineTuningClient.Protocol.cs index 448f3c36..d5bc3233 100644 --- a/src/Custom/FineTuning/FineTuningClient.Protocol.cs +++ b/src/Custom/FineTuning/FineTuningClient.Protocol.cs @@ -30,20 +30,19 @@ public partial class FineTuningClient /// /// [Learn more about fine-tuning](/docs/guides/fine-tuning) /// - /// if the - /// method should return when the service has finished running the - /// operation, or if it should return - /// after the operation has been created but may not have completed - /// processing. + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// is null. /// Service returned a non-success status code. - /// A that can be used to wait for + /// A that can be used to wait for /// the operation to complete, get information about the fine tuning job, or /// cancel the operation. - public virtual async Task CreateJobAsync( - ReturnWhen returnWhen, + public virtual async Task CreateJobAsync( + bool waitUntilCompleted, BinaryContent content, RequestOptions options = null) { @@ -56,14 +55,8 @@ public virtual async Task CreateJobAsync( string jobId = doc.RootElement.GetProperty("id"u8).GetString(); string status = doc.RootElement.GetProperty("status"u8).GetString(); - FineTuningOperation operation = new FineTuningOperation(_pipeline, _endpoint, jobId, status, response); - if (returnWhen == ReturnWhen.Started) - { - return operation; - } - - await operation.WaitForCompletionAsync(options?.CancellationToken ?? default).ConfigureAwait(false); - return operation; + CreateJobOperation operation = new(_pipeline, _endpoint, jobId, status, response); + return await operation.WaitUntilAsync(waitUntilCompleted, options).ConfigureAwait(false); } // CUSTOM: @@ -76,20 +69,19 @@ public virtual async Task CreateJobAsync( /// /// [Learn more about fine-tuning](/docs/guides/fine-tuning) /// - /// if the - /// method should return when the service has finished running the - /// operation, or if it should return - /// after the operation has been created but may not have completed - /// processing. + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// is null. /// Service returned a non-success status code. - /// A that can be used to wait for + /// A that can be used to wait for /// the operation to complete, get information about the fine tuning job, or /// cancel the operation. - public virtual FineTuningOperation CreateJob( - ReturnWhen returnWhen, + public virtual CreateJobOperation CreateJob( + bool waitUntilCompleted, BinaryContent content, RequestOptions options = null) { @@ -102,14 +94,8 @@ public virtual FineTuningOperation CreateJob( string jobId = doc.RootElement.GetProperty("id"u8).GetString(); string status = doc.RootElement.GetProperty("status"u8).GetString(); - FineTuningOperation operation = new FineTuningOperation(_pipeline, _endpoint, jobId, status, response); - if (returnWhen == ReturnWhen.Started) - { - return operation; - } - - operation.WaitForCompletion(options?.CancellationToken ?? default); - return operation; + CreateJobOperation operation = new(_pipeline, _endpoint, jobId, status, response); + return operation.WaitUntil(waitUntilCompleted, options); } // CUSTOM: diff --git a/src/Custom/VectorStores/AddFileToVectorStoreOperation.Protocol.cs b/src/Custom/VectorStores/AddFileToVectorStoreOperation.Protocol.cs new file mode 100644 index 00000000..b5711c9a --- /dev/null +++ b/src/Custom/VectorStores/AddFileToVectorStoreOperation.Protocol.cs @@ -0,0 +1,73 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.ComponentModel; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.VectorStores; + +public partial class AddFileToVectorStoreOperation : OperationResult +{ + private readonly ClientPipeline _pipeline; + private readonly Uri _endpoint; + + private readonly string _vectorStoreId; + private readonly string _fileId; + + private PollingInterval? _pollingInterval; + + /// + public override ContinuationToken? RehydrationToken { get; protected set; } + + /// + public override bool IsCompleted { get; protected set; } + + /// + /// [Protocol Method] Retrieves a vector store file. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task GetFileAssociationAsync(RequestOptions? options) + { + using PipelineMessage message = CreateGetVectorStoreFileRequest(_vectorStoreId, _fileId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Retrieves a vector store file. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult GetFileAssociation(RequestOptions? options) + { + using PipelineMessage message = CreateGetVectorStoreFileRequest(_vectorStoreId, _fileId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + internal PipelineMessage CreateGetVectorStoreFileRequest(string vectorStoreId, string fileId, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/vector_stores/", false); + uri.AppendPath(vectorStoreId, true); + uri.AppendPath("/files/", false); + uri.AppendPath(fileId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); +} diff --git a/src/Custom/VectorStores/AddFileToVectorStoreOperation.cs b/src/Custom/VectorStores/AddFileToVectorStoreOperation.cs new file mode 100644 index 00000000..de4fc796 --- /dev/null +++ b/src/Custom/VectorStores/AddFileToVectorStoreOperation.cs @@ -0,0 +1,194 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.VectorStores; + +[Experimental("OPENAI001")] +public partial class AddFileToVectorStoreOperation : OperationResult +{ + public AddFileToVectorStoreOperation( + ClientPipeline pipeline, + Uri endpoint, + ClientResult result) + : base(result.GetRawResponse()) + { + _pipeline = pipeline; + _endpoint = endpoint; + + Value = result; + Status = Value.Status; + + _vectorStoreId = Value.VectorStoreId; + _fileId = Value.FileId; + + IsCompleted = GetIsCompleted(Value.Status); + RehydrationToken = new AddFileToVectorStoreOperationToken(VectorStoreId, FileId); + } + + /// + /// The current value of the add file to vector store operation in progress. + /// + public VectorStoreFileAssociation? Value { get; private set; } + + /// + /// The current status of the add file to vector store operation in progress. + /// + public VectorStoreFileAssociationStatus? Status { get; private set; } + + /// + /// The ID of the vector store the file is being added to. + /// + public string VectorStoreId { get => _vectorStoreId; } + + /// + /// The ID of the file being added to the vector store. + /// + public string FileId { get => _fileId; } + + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. + /// or is null. + public static async Task RehydrateAsync(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + AddFileToVectorStoreOperationToken token = AddFileToVectorStoreOperationToken.FromToken(rehydrationToken); + + ClientResult result = await client.GetFileAssociationAsync(token.VectorStoreId, token.FileId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + VectorStoreFileAssociation value = VectorStoreFileAssociation.FromResponse(response); + + return new AddFileToVectorStoreOperation(client.Pipeline, client.Endpoint, FromValue(value, response)); + } + + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. + /// or is null. + public static AddFileToVectorStoreOperation Rehydrate(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + AddFileToVectorStoreOperationToken token = AddFileToVectorStoreOperationToken.FromToken(rehydrationToken); + + ClientResult result = client.GetFileAssociation(token.VectorStoreId, token.FileId, cancellationToken.ToRequestOptions()); + PipelineResponse response = result.GetRawResponse(); + VectorStoreFileAssociation value = VectorStoreFileAssociation.FromResponse(response); + + return new AddFileToVectorStoreOperation(client.Pipeline, client.Endpoint, FromValue(value, response)); + } + + /// + public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) + { + _pollingInterval ??= new(); + + while (!IsCompleted) + { + PipelineResponse response = GetRawResponse(); + + await _pollingInterval.WaitAsync(response, cancellationToken); + + ClientResult result = await GetFileAssociationAsync(cancellationToken).ConfigureAwait(false); + + ApplyUpdate(result); + } + } + + public override void WaitForCompletion(CancellationToken cancellationToken = default) + { + _pollingInterval ??= new(); + + while (!IsCompleted) + { + PipelineResponse response = GetRawResponse(); + + _pollingInterval.Wait(response, cancellationToken); + + ClientResult result = GetFileAssociation(cancellationToken); + + ApplyUpdate(result); + } + } + + internal async Task WaitUntilAsync(bool waitUntilCompleted, RequestOptions? options) + { + if (!waitUntilCompleted) return this; + await WaitForCompletionAsync(options?.CancellationToken ?? default).ConfigureAwait(false); + return this; + } + + internal AddFileToVectorStoreOperation WaitUntil(bool waitUntilCompleted, RequestOptions? options) + { + if (!waitUntilCompleted) return this; + WaitForCompletion(options?.CancellationToken ?? default); + return this; + } + + private void ApplyUpdate(ClientResult update) + { + Value = update; + Status = Value.Status; + + IsCompleted = GetIsCompleted(Value.Status); + SetRawResponse(update.GetRawResponse()); + } + + private static bool GetIsCompleted(VectorStoreFileAssociationStatus status) + { + return status == VectorStoreFileAssociationStatus.Completed || + status == VectorStoreFileAssociationStatus.Cancelled || + status == VectorStoreFileAssociationStatus.Failed; + } + + /// + /// Gets a instance representing an existing association between a known + /// vector store ID and file ID. + /// + /// A token that can be used to cancel this method call. + /// A instance. + public virtual async Task> GetFileAssociationAsync(CancellationToken cancellationToken = default) + { + ClientResult result = await GetFileAssociationAsync(cancellationToken.ToRequestOptions()).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + VectorStoreFileAssociation value = VectorStoreFileAssociation.FromResponse(response); + return ClientResult.FromValue(value, response); + } + + /// + /// Gets a instance representing an existing association between a known + /// vector store ID and file ID. + /// + /// A token that can be used to cancel this method call. + /// A instance. + public virtual ClientResult GetFileAssociation(CancellationToken cancellationToken = default) + { + ClientResult result = GetFileAssociation(cancellationToken.ToRequestOptions()); + PipelineResponse response = result.GetRawResponse(); + VectorStoreFileAssociation value = VectorStoreFileAssociation.FromResponse(response); + return ClientResult.FromValue(value, response); + } +} diff --git a/src/Custom/VectorStores/AddFileToVectorStoreOperationToken.cs b/src/Custom/VectorStores/AddFileToVectorStoreOperationToken.cs new file mode 100644 index 00000000..1f8555eb --- /dev/null +++ b/src/Custom/VectorStores/AddFileToVectorStoreOperationToken.cs @@ -0,0 +1,101 @@ +using System; +using System.ClientModel; +using System.Diagnostics; +using System.IO; +using System.Text.Json; + +#nullable enable + +namespace OpenAI.VectorStores; + +internal class AddFileToVectorStoreOperationToken : ContinuationToken +{ + public AddFileToVectorStoreOperationToken(string vectorStoreId, string fileId) + { + VectorStoreId = vectorStoreId; + FileId = fileId; + } + + public string VectorStoreId { get; } + + public string FileId { get; } + + public override BinaryData ToBytes() + { + using MemoryStream stream = new(); + using Utf8JsonWriter writer = new(stream); + writer.WriteStartObject(); + + writer.WriteString("vectorStoreId", VectorStoreId); + writer.WriteString("fileId", FileId); + + writer.WriteEndObject(); + + writer.Flush(); + stream.Position = 0; + + return BinaryData.FromStream(stream); + } + + public static AddFileToVectorStoreOperationToken FromToken(ContinuationToken continuationToken) + { + if (continuationToken is AddFileToVectorStoreOperationToken token) + { + return token; + } + + BinaryData data = continuationToken.ToBytes(); + + if (data.ToMemory().Length == 0) + { + throw new ArgumentException("Failed to create AddFileToVectorStoreOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + Utf8JsonReader reader = new(data); + + string vectorStoreId = null!; + string fileId = null!; + + reader.Read(); + + Debug.Assert(reader.TokenType == JsonTokenType.StartObject); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); + + string propertyName = reader.GetString()!; + + switch (propertyName) + { + case "vectorStoreId": + reader.Read(); + Debug.Assert(reader.TokenType == JsonTokenType.String); + vectorStoreId = reader.GetString()!; + break; + + case "fileId": + reader.Read(); + Debug.Assert(reader.TokenType == JsonTokenType.String); + fileId = reader.GetString()!; + break; + + default: + throw new JsonException($"Unrecognized property '{propertyName}'."); + } + } + + if (vectorStoreId is null || fileId is null) + { + throw new ArgumentException("Failed to create AddFileToVectorStoreOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + return new(vectorStoreId, fileId); + } +} + diff --git a/src/Custom/VectorStores/CreateBatchFileJobOperation.Protocol.cs b/src/Custom/VectorStores/CreateBatchFileJobOperation.Protocol.cs new file mode 100644 index 00000000..44c604e8 --- /dev/null +++ b/src/Custom/VectorStores/CreateBatchFileJobOperation.Protocol.cs @@ -0,0 +1,227 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.ComponentModel; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.VectorStores; + +/// +/// Long-running operation for creating a vector store file batch. +/// +public partial class CreateBatchFileJobOperation : OperationResult +{ + private readonly ClientPipeline _pipeline; + private readonly Uri _endpoint; + + private readonly string _vectorStoreId; + private readonly string _batchId; + + private PollingInterval? _pollingInterval; + + /// + public override ContinuationToken? RehydrationToken { get; protected set; } + + /// + public override bool IsCompleted { get; protected set; } + + // Generated protocol methods + + /// + /// [Protocol Method] Retrieves a vector store file batch. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task GetFileBatchAsync(RequestOptions? options) + { + using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(_vectorStoreId, _batchId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Retrieves a vector store file batch. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult GetFileBatch(RequestOptions? options) + { + using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(_vectorStoreId, _batchId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Cancel a vector store file batch. This attempts to cancel the processing of files in this batch as soon as possible. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task CancelFileBatchAsync(RequestOptions? options) + { + using PipelineMessage message = CreateCancelVectorStoreFileBatchRequest(_vectorStoreId, _batchId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Cancel a vector store file batch. This attempts to cancel the processing of files in this batch as soon as possible. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult CancelFileBatch(RequestOptions? options) + { + using PipelineMessage message = CreateCancelVectorStoreFileBatchRequest(_vectorStoreId, _batchId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + /// + /// [Protocol Method] Returns a paginated collection of vector store files in a batch. + /// + /// + /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the + /// default is 20. + /// + /// + /// Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and`desc` + /// for descending order. Allowed values: "asc" | "desc" + /// + /// + /// A cursor for use in pagination. `after` is an object ID that defines your place in the list. + /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + /// subsequent call can include after=obj_foo in order to fetch the next page of the list. + /// + /// + /// A cursor for use in pagination. `before` is an object ID that defines your place in the list. + /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + /// subsequent call can include before=obj_foo in order to fetch the previous page of the list. + /// + /// Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// A collection of service responses, each holding a page of values. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual IAsyncEnumerable GetFilesInBatchAsync(int? limit, string? order, string? after, string? before, string? filter, RequestOptions? options) + { + VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, _vectorStoreId, _batchId, limit, order, after, before, filter, options); + return PageCollectionHelpers.CreateAsync(enumerator); + } + + /// + /// [Protocol Method] Returns a paginated collection of vector store files in a batch. + /// + /// + /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the + /// default is 20. + /// + /// + /// Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and`desc` + /// for descending order. Allowed values: "asc" | "desc" + /// + /// + /// A cursor for use in pagination. `after` is an object ID that defines your place in the list. + /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + /// subsequent call can include after=obj_foo in order to fetch the next page of the list. + /// + /// + /// A cursor for use in pagination. `before` is an object ID that defines your place in the list. + /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + /// subsequent call can include before=obj_foo in order to fetch the previous page of the list. + /// + /// Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// A collection of service responses, each holding a page of values. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual IEnumerable GetFilesInBatch(int? limit, string? order, string? after, string? before, string? filter, RequestOptions? options) + { + VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, _vectorStoreId, _batchId, limit, order, after, before, filter, options); + return PageCollectionHelpers.Create(enumerator); + } + + internal PipelineMessage CreateGetVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/vector_stores/", false); + uri.AppendPath(vectorStoreId, true); + uri.AppendPath("/file_batches/", false); + uri.AppendPath(batchId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateCancelVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "POST"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/vector_stores/", false); + uri.AppendPath(vectorStoreId, true); + uri.AppendPath("/file_batches/", false); + uri.AppendPath(batchId, true); + uri.AppendPath("/cancel", false); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateGetFilesInVectorStoreBatchesRequest(string vectorStoreId, string batchId, int? limit, string order, string after, string before, string filter, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/vector_stores/", false); + uri.AppendPath(vectorStoreId, true); + uri.AppendPath("/file_batches/", false); + uri.AppendPath(batchId, true); + uri.AppendPath("/files", false); + if (limit != null) + { + uri.AppendQuery("limit", limit.Value, true); + } + if (order != null) + { + uri.AppendQuery("order", order, true); + } + if (after != null) + { + uri.AppendQuery("after", after, true); + } + if (before != null) + { + uri.AppendQuery("before", before, true); + } + if (filter != null) + { + uri.AppendQuery("filter", filter, true); + } + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); +} \ No newline at end of file diff --git a/src/Custom/VectorStores/CreateBatchFileJobOperation.cs b/src/Custom/VectorStores/CreateBatchFileJobOperation.cs new file mode 100644 index 00000000..a34cbae5 --- /dev/null +++ b/src/Custom/VectorStores/CreateBatchFileJobOperation.cs @@ -0,0 +1,335 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.VectorStores; + +/// +/// Long-running operation for creating a vector store file batch. +/// +[Experimental("OPENAI001")] +public partial class CreateBatchFileJobOperation : OperationResult +{ + internal CreateBatchFileJobOperation( + ClientPipeline pipeline, + Uri endpoint, + ClientResult result) + : base(result.GetRawResponse()) + { + _pipeline = pipeline; + _endpoint = endpoint; + + Value = result; + Status = Value.Status; + + _vectorStoreId = Value.VectorStoreId; + _batchId = Value.BatchId; + + IsCompleted = GetIsCompleted(Value.Status); + RehydrationToken = new CreateBatchFileJobOperationToken(VectorStoreId, BatchId); + } + + /// + /// The current value of the in progress. + /// + public VectorStoreBatchFileJob? Value { get; private set; } + + /// + /// The current status of the in progress. + /// + public VectorStoreBatchFileJobStatus? Status { get; private set; } + + /// + /// The ID of the vector store corresponding to this batch file operation. + /// + public string VectorStoreId { get => _vectorStoreId; } + + /// + /// The ID of the batch file job represented by this operation. + /// + public string BatchId { get => _batchId; } + + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. + /// or is null. + public static async Task RehydrateAsync(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + CreateBatchFileJobOperationToken token = CreateBatchFileJobOperationToken.FromToken(rehydrationToken); + + ClientResult result = await client.GetBatchFileJobAsync(token.VectorStoreId, token.BatchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + VectorStoreBatchFileJob job = VectorStoreBatchFileJob.FromResponse(response); + + return new CreateBatchFileJobOperation(client.Pipeline, client.Endpoint, FromValue(job, response)); + } + + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. + /// or is null. + public static CreateBatchFileJobOperation Rehydrate(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + CreateBatchFileJobOperationToken token = CreateBatchFileJobOperationToken.FromToken(rehydrationToken); + + ClientResult result = client.GetBatchFileJob(token.VectorStoreId, token.BatchId, cancellationToken.ToRequestOptions()); + PipelineResponse response = result.GetRawResponse(); + VectorStoreBatchFileJob job = VectorStoreBatchFileJob.FromResponse(response); + + return new CreateBatchFileJobOperation(client.Pipeline, client.Endpoint, FromValue(job, response)); + } + + /// + public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) + { + _pollingInterval ??= new(); + + while (!IsCompleted) + { + PipelineResponse response = GetRawResponse(); + + await _pollingInterval.WaitAsync(response, cancellationToken); + + ClientResult result = await GetFileBatchAsync(cancellationToken).ConfigureAwait(false); + + ApplyUpdate(result); + } + } + + /// + public override void WaitForCompletion(CancellationToken cancellationToken = default) + { + _pollingInterval ??= new(); + + while (!IsCompleted) + { + PipelineResponse response = GetRawResponse(); + + _pollingInterval.Wait(response, cancellationToken); + + ClientResult result = GetFileBatch(cancellationToken); + + ApplyUpdate(result); + } + } + + internal async Task WaitUntilAsync(bool waitUntilCompleted, RequestOptions? options) + { + if (!waitUntilCompleted) return this; + await WaitForCompletionAsync(options?.CancellationToken ?? default).ConfigureAwait(false); + return this; + } + + internal CreateBatchFileJobOperation WaitUntil(bool waitUntilCompleted, RequestOptions? options) + { + if (!waitUntilCompleted) return this; + WaitForCompletion(options?.CancellationToken ?? default); + return this; + } + + private void ApplyUpdate(ClientResult update) + { + Value = update; + Status = Value.Status; + + IsCompleted = GetIsCompleted(Value.Status); + SetRawResponse(update.GetRawResponse()); + } + + private static bool GetIsCompleted(VectorStoreBatchFileJobStatus status) + { + return status == VectorStoreBatchFileJobStatus.Completed || + status == VectorStoreBatchFileJobStatus.Cancelled || + status == VectorStoreBatchFileJobStatus.Failed; + } + + // Generated convenience methods + + /// + /// Gets an existing vector store batch file ingestion job from a known vector store ID and job ID. + /// + /// A token that can be used to cancel this method call. + /// A instance representing the ingestion operation. + public virtual async Task> GetFileBatchAsync(CancellationToken cancellationToken = default) + { + ClientResult result = await GetFileBatchAsync(cancellationToken.ToRequestOptions()).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); + return ClientResult.FromValue(value, response); + } + + /// + /// Gets an existing vector store batch file ingestion job from a known vector store ID and job ID. + /// + /// A token that can be used to cancel this method call. + /// A instance representing the ingestion operation. + public virtual ClientResult GetFileBatch(CancellationToken cancellationToken = default) + { + ClientResult result = GetFileBatch(cancellationToken.ToRequestOptions()); + PipelineResponse response = result.GetRawResponse(); + VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); + return ClientResult.FromValue(value, response); + } + + /// + /// Cancels an in-progress . + /// + /// A token that can be used to cancel this method call. + /// An updated instance. + public virtual async Task> CancelFileBatchAsync(CancellationToken cancellationToken = default) + { + ClientResult result = await CancelFileBatchAsync(cancellationToken.ToRequestOptions()).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); + return ClientResult.FromValue(value, response); + } + + /// + /// Cancels an in-progress . + /// + /// A token that can be used to cancel this method call. + /// An updated instance. + public virtual ClientResult CancelFileBatch(CancellationToken cancellationToken = default) + { + ClientResult result = CancelFileBatch(cancellationToken.ToRequestOptions()); + PipelineResponse response = result.GetRawResponse(); + VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); + return ClientResult.FromValue(value, response); + } + + /// + /// Gets a page collection of file associations associated with a vector store batch file job, representing the files + /// that were scheduled for ingestion into the vector store. + /// + /// Options describing the collection to return. + /// A token that can be used to cancel this method call. + /// holds pages of values. To obtain a collection of values, call + /// . To obtain the current + /// page of values, call . + /// A collection of pages of . + public virtual AsyncPageCollection GetFilesInBatchAsync( + VectorStoreFileAssociationCollectionOptions? options = default, + CancellationToken cancellationToken = default) + { + return GetFilesInBatchAsync(options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, options?.Filter?.ToString(), cancellationToken.ToRequestOptions()) is not AsyncPageCollection pages + ? throw new NotSupportedException("Failed to cast protocol method return type to AsyncPageCollection.") + : pages; + } + + /// + /// Rehydrates a page collection of file associations from a page token. + /// + /// Page token corresponding to the first page of the collection to rehydrate. + /// A token that can be used to cancel this method call. + /// holds pages of values. To obtain a collection of values, call + /// . To obtain the current + /// page of values, call . + /// A collection of pages of . + public virtual AsyncPageCollection GetFilesInBatchAsync( + ContinuationToken firstPageToken, + CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); + + VectorStoreFileBatchesPageToken pageToken = VectorStoreFileBatchesPageToken.FromToken(firstPageToken); + + if (_vectorStoreId != pageToken.VectorStoreId) + { + throw new ArgumentException( + "Invalid page token. 'VectorStoreId' value does not match page token value.", + nameof(VectorStoreId)); + } + + if (_batchId != pageToken.BatchId) + { + throw new ArgumentException( + "Invalid page token. 'BatchId' value does not match page token value.", + nameof(BatchId)); + } + + return GetFilesInBatchAsync(pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken?.Before, pageToken?.Filter, cancellationToken.ToRequestOptions()) is not AsyncPageCollection pages + ? throw new NotSupportedException("Failed to cast protocol method return type to PageCollection.") + : pages; + } + + /// + /// Gets a page collection of file associations associated with a vector store batch file job, representing the files + /// that were scheduled for ingestion into the vector store. + /// + /// Options describing the collection to return. + /// A token that can be used to cancel this method call. + /// holds pages of values. To obtain a collection of values, call + /// . To obtain the current + /// page of values, call . + /// A collection of pages of . + public virtual PageCollection GetFilesInBatch( + VectorStoreFileAssociationCollectionOptions? options = default, + CancellationToken cancellationToken = default) + { + return GetFilesInBatch(options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, options?.Filter?.ToString(), cancellationToken.ToRequestOptions()) is not PageCollection pages + ? throw new NotSupportedException("Failed to cast protocol method return type to AsyncPageCollection.") + : pages; + } + + /// + /// Rehydrates a page collection of file associations from a page token. + /// that were scheduled for ingestion into the vector store. + /// + /// Page token corresponding to the first page of the collection to rehydrate. + /// A token that can be used to cancel this method call. + /// holds pages of values. To obtain a collection of values, call + /// . To obtain the current + /// page of values, call . + /// A collection of pages of . + public virtual PageCollection GetFilesInBatch( + ContinuationToken firstPageToken, + CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); + + VectorStoreFileBatchesPageToken pageToken = VectorStoreFileBatchesPageToken.FromToken(firstPageToken); + + if (VectorStoreId != pageToken.VectorStoreId) + { + throw new ArgumentException( + "Invalid page token. 'VectorStoreId' value does not match page token value.", + nameof(VectorStoreId)); + } + + if (BatchId != pageToken.BatchId) + { + throw new ArgumentException( + "Invalid page token. 'BatchId' value does not match page token value.", + nameof(BatchId)); + } + + return GetFilesInBatch(pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken?.Before, pageToken?.Filter, cancellationToken.ToRequestOptions()) is not PageCollection pages + ? throw new NotSupportedException("Failed to cast protocol method return type to PageCollection.") + : pages; + } +} \ No newline at end of file diff --git a/src/Custom/VectorStores/CreateBatchFileJobOperationToken.cs b/src/Custom/VectorStores/CreateBatchFileJobOperationToken.cs new file mode 100644 index 00000000..20e47b4d --- /dev/null +++ b/src/Custom/VectorStores/CreateBatchFileJobOperationToken.cs @@ -0,0 +1,101 @@ +using System; +using System.ClientModel; +using System.Diagnostics; +using System.IO; +using System.Text.Json; + +#nullable enable + +namespace OpenAI.VectorStores; + +internal class CreateBatchFileJobOperationToken : ContinuationToken +{ + public CreateBatchFileJobOperationToken(string vectorStoreId, string batchId) + { + VectorStoreId = vectorStoreId; + BatchId = batchId; + } + + public string VectorStoreId { get; } + + public string BatchId { get; } + + public override BinaryData ToBytes() + { + using MemoryStream stream = new(); + using Utf8JsonWriter writer = new(stream); + writer.WriteStartObject(); + + writer.WriteString("vectorStoreId", VectorStoreId); + writer.WriteString("batchId", BatchId); + + writer.WriteEndObject(); + + writer.Flush(); + stream.Position = 0; + + return BinaryData.FromStream(stream); + } + + public static CreateBatchFileJobOperationToken FromToken(ContinuationToken continuationToken) + { + if (continuationToken is CreateBatchFileJobOperationToken token) + { + return token; + } + + BinaryData data = continuationToken.ToBytes(); + + if (data.ToMemory().Length == 0) + { + throw new ArgumentException("Failed to create AddFileBatchToVectorStoreOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + Utf8JsonReader reader = new(data); + + string vectorStoreId = null!; + string batchId = null!; + + reader.Read(); + + Debug.Assert(reader.TokenType == JsonTokenType.StartObject); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); + + string propertyName = reader.GetString()!; + + switch (propertyName) + { + case "vectorStoreId": + reader.Read(); + Debug.Assert(reader.TokenType == JsonTokenType.String); + vectorStoreId = reader.GetString()!; + break; + + case "batchId": + reader.Read(); + Debug.Assert(reader.TokenType == JsonTokenType.String); + batchId = reader.GetString()!; + break; + + default: + throw new JsonException($"Unrecognized property '{propertyName}'."); + } + } + + if (vectorStoreId is null || batchId is null) + { + throw new ArgumentException("Failed to create AddFileBatchToVectorStoreOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + return new(vectorStoreId, batchId); + } +} + diff --git a/src/Custom/VectorStores/CreateVectorStoreOperation.Protocol.cs b/src/Custom/VectorStores/CreateVectorStoreOperation.Protocol.cs new file mode 100644 index 00000000..62669416 --- /dev/null +++ b/src/Custom/VectorStores/CreateVectorStoreOperation.Protocol.cs @@ -0,0 +1,70 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.ComponentModel; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.VectorStores; + +public partial class CreateVectorStoreOperation : OperationResult +{ + private readonly ClientPipeline _pipeline; + private readonly Uri _endpoint; + + private readonly string _vectorStoreId; + + private PollingInterval? _pollingInterval; + + /// + public override ContinuationToken? RehydrationToken { get; protected set; } + + /// + public override bool IsCompleted { get; protected set; } + + /// + /// [Protocol Method] Retrieves a vector store. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task GetVectorStoreAsync(RequestOptions? options) + { + using PipelineMessage message = CreateGetVectorStoreRequest(_vectorStoreId, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + /// + /// [Protocol Method] Retrieves a vector store. + /// + /// The request options, which can override default behaviors of the client pipeline on a per-call basis. + /// Service returned a non-success status code. + /// The response returned from the service. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual ClientResult GetVectorStore(RequestOptions? options) + { + using PipelineMessage message = CreateGetVectorStoreRequest(_vectorStoreId, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + + internal PipelineMessage CreateGetVectorStoreRequest(string vectorStoreId, RequestOptions? options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/vector_stores/", false); + uri.AppendPath(vectorStoreId, true); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); +} diff --git a/src/Custom/VectorStores/CreateVectorStoreOperation.cs b/src/Custom/VectorStores/CreateVectorStoreOperation.cs new file mode 100644 index 00000000..47aac950 --- /dev/null +++ b/src/Custom/VectorStores/CreateVectorStoreOperation.cs @@ -0,0 +1,184 @@ +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Diagnostics.CodeAnalysis; +using System.Threading; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI.VectorStores; + +[Experimental("OPENAI001")] +public partial class CreateVectorStoreOperation : OperationResult +{ + public CreateVectorStoreOperation( + ClientPipeline pipeline, + Uri endpoint, + ClientResult result) + : base(result.GetRawResponse()) + { + _pipeline = pipeline; + _endpoint = endpoint; + + Value = result; + Status = Value.Status; + + _vectorStoreId = Value.Id; + + IsCompleted = GetIsCompleted(Value.Status); + RehydrationToken = new CreateVectorStoreOperationToken(VectorStoreId); + } + + /// + /// The current value of the create operation in progress. + /// + public VectorStore? Value { get; private set; } + + /// + /// The current status of the create operation in progress. + /// + public VectorStoreStatus? Status { get; private set; } + + /// + /// The ID of the vector store being created. + /// + public string VectorStoreId { get => _vectorStoreId; } + + + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. + /// or is null. + public static async Task RehydrateAsync(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + CreateVectorStoreOperationToken token = CreateVectorStoreOperationToken.FromToken(rehydrationToken); + + ClientResult result = await client.GetVectorStoreAsync(token.VectorStoreId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + VectorStore vectorStore = VectorStore.FromResponse(response); + + return new CreateVectorStoreOperation(client.Pipeline, client.Endpoint, FromValue(vectorStore, response)); + } + + /// + /// Recreates a from a rehydration token. + /// + /// The used to obtain the + /// operation status from the service. + /// The rehydration token corresponding to + /// the operation to rehydrate. + /// A token that can be used to cancel the + /// request. + /// The rehydrated operation. + /// or is null. + public static CreateVectorStoreOperation Rehydrate(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(client, nameof(client)); + Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); + + CreateVectorStoreOperationToken token = CreateVectorStoreOperationToken.FromToken(rehydrationToken); + + ClientResult result = client.GetVectorStore(token.VectorStoreId, cancellationToken.ToRequestOptions()); + PipelineResponse response = result.GetRawResponse(); + VectorStore vectorStore = VectorStore.FromResponse(response); + + return new CreateVectorStoreOperation(client.Pipeline, client.Endpoint, FromValue(vectorStore, response)); + } + + /// + public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) + { + _pollingInterval ??= new(); + + while (!IsCompleted) + { + PipelineResponse response = GetRawResponse(); + + await _pollingInterval.WaitAsync(response, cancellationToken); + + ClientResult result = await GetVectorStoreAsync(cancellationToken).ConfigureAwait(false); + + ApplyUpdate(result); + } + } + + public override void WaitForCompletion(CancellationToken cancellationToken = default) + { + _pollingInterval ??= new(); + + while (!IsCompleted) + { + PipelineResponse response = GetRawResponse(); + + _pollingInterval.Wait(response, cancellationToken); + + ClientResult result = GetVectorStore(cancellationToken); + + ApplyUpdate(result); + } + } + + internal async Task WaitUntilAsync(bool waitUntilCompleted, RequestOptions? options) + { + if (!waitUntilCompleted) return this; + await WaitForCompletionAsync(options?.CancellationToken ?? default).ConfigureAwait(false); + return this; + } + + internal CreateVectorStoreOperation WaitUntil(bool waitUntilCompleted, RequestOptions? options) + { + if (!waitUntilCompleted) return this; + WaitForCompletion(options?.CancellationToken ?? default); + return this; + } + + private void ApplyUpdate(ClientResult update) + { + Value = update; + Status = Value.Status; + + IsCompleted = GetIsCompleted(Value.Status); + SetRawResponse(update.GetRawResponse()); + } + + private static bool GetIsCompleted(VectorStoreStatus status) + { + return status == VectorStoreStatus.Completed || + status == VectorStoreStatus.Expired; + } + + /// + /// Gets an instance representing an existing . + /// + /// A token that can be used to cancel this method call. + /// A representation of an existing . + public virtual async Task> GetVectorStoreAsync(CancellationToken cancellationToken = default) + { + ClientResult result + = await GetVectorStoreAsync(cancellationToken.ToRequestOptions()).ConfigureAwait(false); + return ClientResult.FromValue( + VectorStore.FromResponse(result.GetRawResponse()), result.GetRawResponse()); + } + + /// + /// Gets an instance representing an existing . + /// + /// A token that can be used to cancel this method call. + /// A representation of an existing . + public virtual ClientResult GetVectorStore(CancellationToken cancellationToken = default) + { + ClientResult result = GetVectorStore(cancellationToken.ToRequestOptions()); + return ClientResult.FromValue(VectorStore.FromResponse(result.GetRawResponse()), result.GetRawResponse()); + } +} diff --git a/src/Custom/VectorStores/CreateVectorStoreOperationToken.cs b/src/Custom/VectorStores/CreateVectorStoreOperationToken.cs new file mode 100644 index 00000000..00eca795 --- /dev/null +++ b/src/Custom/VectorStores/CreateVectorStoreOperationToken.cs @@ -0,0 +1,90 @@ +using System; +using System.ClientModel; +using System.Diagnostics; +using System.IO; +using System.Text.Json; + +#nullable enable + +namespace OpenAI.VectorStores; + +internal class CreateVectorStoreOperationToken : ContinuationToken +{ + public CreateVectorStoreOperationToken(string vectorStoreId) + { + VectorStoreId = vectorStoreId; + } + + public string VectorStoreId { get; } + + public override BinaryData ToBytes() + { + using MemoryStream stream = new(); + using Utf8JsonWriter writer = new(stream); + writer.WriteStartObject(); + + writer.WriteString("vectorStoreId", VectorStoreId); + + writer.WriteEndObject(); + + writer.Flush(); + stream.Position = 0; + + return BinaryData.FromStream(stream); + } + + public static CreateVectorStoreOperationToken FromToken(ContinuationToken continuationToken) + { + if (continuationToken is CreateVectorStoreOperationToken token) + { + return token; + } + + BinaryData data = continuationToken.ToBytes(); + + if (data.ToMemory().Length == 0) + { + throw new ArgumentException("Failed to create CreateVectorStoreOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + Utf8JsonReader reader = new(data); + + string vectorStoreId = null!; + + reader.Read(); + + Debug.Assert(reader.TokenType == JsonTokenType.StartObject); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); + + string propertyName = reader.GetString()!; + + switch (propertyName) + { + case "vectorStoreId": + reader.Read(); + Debug.Assert(reader.TokenType == JsonTokenType.String); + vectorStoreId = reader.GetString()!; + break; + + default: + throw new JsonException($"Unrecognized property '{propertyName}'."); + } + } + + if (vectorStoreId is null) + { + throw new ArgumentException("Failed to create CreateVectorStoreOperationToken from provided continuationToken.", nameof(continuationToken)); + } + + return new(vectorStoreId); + } +} + diff --git a/src/Custom/VectorStores/Internal/Pagination/VectorStoreFileBatchesPageEnumerator.cs b/src/Custom/VectorStores/Internal/Pagination/VectorStoreFileBatchesPageEnumerator.cs index cd4f938e..71ce2862 100644 --- a/src/Custom/VectorStores/Internal/Pagination/VectorStoreFileBatchesPageEnumerator.cs +++ b/src/Custom/VectorStores/Internal/Pagination/VectorStoreFileBatchesPageEnumerator.cs @@ -20,15 +20,17 @@ internal partial class VectorStoreFileBatchesPageEnumerator : PageEnumerator _pipeline; + public VectorStoreFileBatchesPageEnumerator( ClientPipeline pipeline, Uri endpoint, string vectorStoreId, string batchId, int? limit, string? order, string? after, string? before, string? filter, - RequestOptions options) + RequestOptions? options) { _pipeline = pipeline; _endpoint = endpoint; @@ -93,7 +95,7 @@ public override PageResult GetPageFromResult(ClientR return PageResult.Create(list.Data, pageToken, nextPageToken, response); } - internal virtual async Task GetFileAssociationsAsync(string vectorStoreId, string batchId, int? limit, string? order, string? after, string? before, string? filter, RequestOptions options) + internal virtual async Task GetFileAssociationsAsync(string vectorStoreId, string batchId, int? limit, string? order, string? after, string? before, string? filter, RequestOptions? options) { Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); @@ -102,7 +104,7 @@ internal virtual async Task GetFileAssociationsAsync(string vector return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); } - internal virtual ClientResult GetFileAssociations(string vectorStoreId, string batchId, int? limit, string? order, string? after, string? before, string? filter, RequestOptions options) + internal virtual ClientResult GetFileAssociations(string vectorStoreId, string batchId, int? limit, string? order, string? after, string? before, string? filter, RequestOptions? options) { Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); @@ -111,7 +113,7 @@ internal virtual ClientResult GetFileAssociations(string vectorStoreId, string b return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - internal PipelineMessage CreateGetFilesInVectorStoreBatchesRequest(string vectorStoreId, string batchId, int? limit, string? order, string? after, string? before, string? filter, RequestOptions options) + internal PipelineMessage CreateGetFilesInVectorStoreBatchesRequest(string vectorStoreId, string batchId, int? limit, string? order, string? after, string? before, string? filter, RequestOptions? options) { var message = _pipeline.CreateMessage(); message.ResponseClassifier = PipelineMessageClassifier200; diff --git a/src/Custom/VectorStores/Internal/Pagination/VectorStoreFilesPageEnumerator.cs b/src/Custom/VectorStores/Internal/Pagination/VectorStoreFilesPageEnumerator.cs index 3063fb39..9a5e9bec 100644 --- a/src/Custom/VectorStores/Internal/Pagination/VectorStoreFilesPageEnumerator.cs +++ b/src/Custom/VectorStores/Internal/Pagination/VectorStoreFilesPageEnumerator.cs @@ -23,6 +23,8 @@ internal partial class VectorStoreFilesPageEnumerator : PageEnumerator _pipeline; + public VectorStoreFilesPageEnumerator( ClientPipeline pipeline, Uri endpoint, diff --git a/src/Custom/VectorStores/Internal/Pagination/VectorStoresPageEnumerator.cs b/src/Custom/VectorStores/Internal/Pagination/VectorStoresPageEnumerator.cs index 3e454f38..311a8837 100644 --- a/src/Custom/VectorStores/Internal/Pagination/VectorStoresPageEnumerator.cs +++ b/src/Custom/VectorStores/Internal/Pagination/VectorStoresPageEnumerator.cs @@ -20,6 +20,8 @@ internal partial class VectorStoresPageEnumerator : PageEnumerator private string _after; + public virtual ClientPipeline Pipeline => _pipeline; + public VectorStoresPageEnumerator( ClientPipeline pipeline, Uri endpoint, @@ -96,7 +98,7 @@ internal virtual ClientResult GetVectorStores(int? limit, string order, string a return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); } - private PipelineMessage CreateGetVectorStoresRequest(int? limit, string order, string after, string before, RequestOptions options) + internal PipelineMessage CreateGetVectorStoresRequest(int? limit, string order, string after, string before, RequestOptions options) { var message = _pipeline.CreateMessage(); message.ResponseClassifier = PipelineMessageClassifier200; diff --git a/src/Custom/VectorStores/VectorStoreClient.Convenience.cs b/src/Custom/VectorStores/VectorStoreClient.Convenience.cs index b7653e79..581b07f2 100644 --- a/src/Custom/VectorStores/VectorStoreClient.Convenience.cs +++ b/src/Custom/VectorStores/VectorStoreClient.Convenience.cs @@ -61,24 +61,30 @@ public virtual ClientResult DeleteVectorStore(VectorStore vectorStore) /// /// Associates an uploaded file with a vector store, beginning ingestion of the file into the vector store. /// + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The vector store to associate the file with. /// The file to associate with the vector store. - /// - /// A instance that represents the new association. - /// - public virtual Task> AddFileToVectorStoreAsync(VectorStore vectorStore, OpenAIFileInfo file) - => AddFileToVectorStoreAsync(vectorStore?.Id, file?.Id); + /// A that can be used to wait for + /// the vector store file addition to complete. + public async virtual Task AddFileToVectorStoreAsync(bool waitUntilCompleted, VectorStore vectorStore, OpenAIFileInfo file) + => await AddFileToVectorStoreAsync(waitUntilCompleted, vectorStore?.Id, file?.Id).ConfigureAwait(false); /// /// Associates an uploaded file with a vector store, beginning ingestion of the file into the vector store. /// + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The vector store to associate the file with. /// The file to associate with the vector store. - /// - /// A instance that represents the new association. - /// - public virtual ClientResult AddFileToVectorStore(VectorStore vectorStore, OpenAIFileInfo file) - => AddFileToVectorStore(vectorStore?.Id, file?.Id); + /// A that can be used to wait for + /// the vector store file addition to complete. + public virtual AddFileToVectorStoreOperation AddFileToVectorStore(bool waitUntilCompleted, VectorStore vectorStore, OpenAIFileInfo file) + => AddFileToVectorStore(waitUntilCompleted, vectorStore?.Id, file?.Id); /// /// Gets a page collection holding instances that represent file inclusions in the @@ -167,30 +173,28 @@ public virtual ClientResult RemoveFileFromStore(VectorStore vectorStore, O /// /// Begins a batch job to associate multiple jobs with a vector store, beginning the ingestion process. /// - /// if the - /// method should return when the service has finished running the - /// operation, or if it should return - /// after the operation has been created but may not have completed - /// processing. + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The vector store to associate files with. /// The files to associate with the vector store. - /// A that can be used to wait for + /// A that can be used to wait for /// the operation to complete, get information about the batch file job, or cancel the operation. - public virtual Task CreateBatchFileJobAsync(ReturnWhen returnWhen, VectorStore vectorStore, IEnumerable files) - => CreateBatchFileJobAsync(returnWhen, vectorStore?.Id, files?.Select(file => file.Id)); + public virtual Task CreateBatchFileJobAsync(bool waitUntilCompleted, VectorStore vectorStore, IEnumerable files) + => CreateBatchFileJobAsync(waitUntilCompleted, vectorStore?.Id, files?.Select(file => file.Id)); /// /// Begins a batch job to associate multiple jobs with a vector store, beginning the ingestion process. /// - /// if the - /// method should return when the service has finished running the - /// operation, or if it should return - /// after the operation has been created but may not have completed - /// processing. + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The vector store to associate files with. /// The files to associate with the vector store. - /// A that can be used to wait for + /// A that can be used to wait for /// the operation to complete, get information about the batch file job, or cancel the operation. - public virtual VectorStoreFileBatchOperation CreateBatchFileJob(ReturnWhen returnWhen, VectorStore vectorStore, IEnumerable files) - => CreateBatchFileJob(returnWhen, vectorStore?.Id, files?.Select(file => file.Id)); + public virtual CreateBatchFileJobOperation CreateBatchFileJob(bool waitUntilCompleted, VectorStore vectorStore, IEnumerable files) + => CreateBatchFileJob(waitUntilCompleted, vectorStore?.Id, files?.Select(file => file.Id)); } diff --git a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs index 95158c8a..864716e4 100644 --- a/src/Custom/VectorStores/VectorStoreClient.Protocol.cs +++ b/src/Custom/VectorStores/VectorStoreClient.Protocol.cs @@ -90,30 +90,49 @@ public virtual IEnumerable GetVectorStores(int? limit, string orde /// /// [Protocol Method] Creates a vector store. /// + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// is null. /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task CreateVectorStoreAsync(BinaryContent content, RequestOptions options = null) + /// A that can be used to wait for + /// the vector store creation to complete. + [EditorBrowsable(EditorBrowsableState.Never)] + public virtual async Task CreateVectorStoreAsync(bool waitUntilCompleted, BinaryContent content, RequestOptions options = null) { using PipelineMessage message = CreateCreateVectorStoreRequest(content, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + PipelineResponse response = await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false); + VectorStore value = VectorStore.FromResponse(response); + + CreateVectorStoreOperation operation = new(_pipeline, _endpoint, ClientResult.FromValue(value, response)); + return await operation.WaitUntilAsync(waitUntilCompleted, options).ConfigureAwait(false); } /// /// [Protocol Method] Creates a vector store. /// + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// is null. /// Service returned a non-success status code. - /// The response returned from the service. + /// A that can be used to wait for + /// the vector store creation to complete. [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult CreateVectorStore(BinaryContent content, RequestOptions options = null) + public virtual CreateVectorStoreOperation CreateVectorStore(bool waitUntilCompleted, BinaryContent content, RequestOptions options = null) { using PipelineMessage message = CreateCreateVectorStoreRequest(content, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + PipelineResponse response = _pipeline.ProcessMessage(message, options); + VectorStore value = VectorStore.FromResponse(response); + + CreateVectorStoreOperation operation = new(_pipeline, _endpoint, ClientResult.FromValue(value, response)); + return operation.WaitUntil(waitUntilCompleted, options); } /// @@ -305,41 +324,59 @@ public virtual IEnumerable GetFileAssociations(string vectorStoreI /// /// [Protocol Method] Create a vector store file by attaching a [File](/docs/api-reference/files) to a [vector store](/docs/api-reference/vector-stores/object). /// + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The ID of the vector store for which to create a File. /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// or is null. /// is an empty string, and was expected to be non-empty. /// Service returned a non-success status code. - /// The response returned from the service. + /// A that can be used to wait for + /// the vector store file addition to complete. [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task AddFileToVectorStoreAsync(string vectorStoreId, BinaryContent content, RequestOptions options = null) + public virtual async Task AddFileToVectorStoreAsync(bool waitUntilCompleted, string vectorStoreId, BinaryContent content, RequestOptions options = null) { Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); Argument.AssertNotNull(content, nameof(content)); using PipelineMessage message = CreateCreateVectorStoreFileRequest(vectorStoreId, content, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + PipelineResponse response = await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false); + VectorStoreFileAssociation value = VectorStoreFileAssociation.FromResponse(response); + + AddFileToVectorStoreOperation operation = new(_pipeline, _endpoint, ClientResult.FromValue(value, response)); + return await operation.WaitUntilAsync(waitUntilCompleted, options).ConfigureAwait(false); } /// /// [Protocol Method] Create a vector store file by attaching a [File](/docs/api-reference/files) to a [vector store](/docs/api-reference/vector-stores/object). /// + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The ID of the vector store for which to create a File. /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// or is null. /// is an empty string, and was expected to be non-empty. /// Service returned a non-success status code. - /// The response returned from the service. + /// A that can be used to wait for + /// the vector store file addition to complete. [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult AddFileToVectorStore(string vectorStoreId, BinaryContent content, RequestOptions options = null) + public virtual AddFileToVectorStoreOperation AddFileToVectorStore(bool waitUntilCompleted, string vectorStoreId, BinaryContent content, RequestOptions options = null) { Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); Argument.AssertNotNull(content, nameof(content)); using PipelineMessage message = CreateCreateVectorStoreFileRequest(vectorStoreId, content, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + PipelineResponse response = _pipeline.ProcessMessage(message, options); + VectorStoreFileAssociation value = VectorStoreFileAssociation.FromResponse(response); + + AddFileToVectorStoreOperation operation = new(_pipeline, _endpoint, ClientResult.FromValue(value, response)); + return operation.WaitUntil(waitUntilCompleted, options); } /// @@ -425,22 +462,21 @@ public virtual ClientResult RemoveFileFromStore(string vectorStoreId, string fil /// /// [Protocol Method] Create a vector store file batch. /// - /// if the - /// method should return when the service has finished running the - /// operation, or if it should return - /// after the operation has been created but may not have completed - /// processing. + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The ID of the vector store for which to create a file batch. /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// or is null. /// is an empty string, and was expected to be non-empty. /// Service returned a non-success status code. - /// A that can be used to wait for + /// A that can be used to wait for /// the operation to complete, get information about the batch file job, or cancel the operation. [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task CreateBatchFileJobAsync( - ReturnWhen returnWhen, + public virtual async Task CreateBatchFileJobAsync( + bool waitUntilCompleted, string vectorStoreId, BinaryContent content, RequestOptions options = null) @@ -452,35 +488,28 @@ public virtual async Task CreateBatchFileJobAsync PipelineResponse response = await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false); VectorStoreBatchFileJob job = VectorStoreBatchFileJob.FromResponse(response); - VectorStoreFileBatchOperation operation = new(_pipeline, _endpoint, ClientResult.FromValue(job, response)); - if (returnWhen == ReturnWhen.Started) - { - return operation; - } - - await operation.WaitForCompletionAsync(options?.CancellationToken ?? default).ConfigureAwait(false); - return operation; + CreateBatchFileJobOperation operation = new(_pipeline, _endpoint, ClientResult.FromValue(job, response)); + return await operation.WaitUntilAsync(waitUntilCompleted, options).ConfigureAwait(false); } /// /// [Protocol Method] Create a vector store file batch. /// - /// if the - /// method should return when the service has finished running the - /// operation, or if it should return - /// after the operation has been created but may not have completed - /// processing. + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The ID of the vector store for which to create a file batch. /// The content to send as the body of the request. /// The request options, which can override default behaviors of the client pipeline on a per-call basis. /// or is null. /// is an empty string, and was expected to be non-empty. /// Service returned a non-success status code. - /// A that can be used to wait for + /// A that can be used to wait for /// the operation to complete, get information about the batch file job, or cancel the operation. [EditorBrowsable(EditorBrowsableState.Never)] - public virtual VectorStoreFileBatchOperation CreateBatchFileJob( - ReturnWhen returnWhen, + public virtual CreateBatchFileJobOperation CreateBatchFileJob( + bool waitUntilCompleted, string vectorStoreId, BinaryContent content, RequestOptions options = null) @@ -492,14 +521,8 @@ public virtual VectorStoreFileBatchOperation CreateBatchFileJob( PipelineResponse response = _pipeline.ProcessMessage(message, options); VectorStoreBatchFileJob job = VectorStoreBatchFileJob.FromResponse(response); - VectorStoreFileBatchOperation operation = new(_pipeline, _endpoint, ClientResult.FromValue(job, response)); - if (returnWhen == ReturnWhen.Started) - { - return operation; - } - - operation.WaitForCompletion(options?.CancellationToken ?? default); - return operation; + CreateBatchFileJobOperation operation = new(_pipeline, _endpoint, ClientResult.FromValue(job, response)); + return operation.WaitUntil(waitUntilCompleted, options); } /// diff --git a/src/Custom/VectorStores/VectorStoreClient.cs b/src/Custom/VectorStores/VectorStoreClient.cs index 6be53f8d..e0d61c27 100644 --- a/src/Custom/VectorStores/VectorStoreClient.cs +++ b/src/Custom/VectorStores/VectorStoreClient.cs @@ -84,27 +84,35 @@ protected internal VectorStoreClient(ClientPipeline pipeline, Uri endpoint, Open } /// Creates a vector store. + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The to use. /// A token that can be used to cancel this method call. /// is null. - /// Create vector store. - public virtual async Task> CreateVectorStoreAsync(VectorStoreCreationOptions vectorStore = null, CancellationToken cancellationToken = default) + /// A that can be used to wait for + /// the vector store creation to complete. + public virtual async Task CreateVectorStoreAsync(bool waitUntilCompleted, VectorStoreCreationOptions vectorStore = null, CancellationToken cancellationToken = default) { using BinaryContent content = vectorStore?.ToBinaryContent(); - ClientResult result = await CreateVectorStoreAsync(content, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - return ClientResult.FromValue(VectorStore.FromResponse(result.GetRawResponse()), result.GetRawResponse()); + return await CreateVectorStoreAsync(waitUntilCompleted, content, cancellationToken.ToRequestOptions()).ConfigureAwait(false); } /// Creates a vector store. + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The to use. /// A token that can be used to cancel this method call. /// is null. - /// Create vector store. - public virtual ClientResult CreateVectorStore(VectorStoreCreationOptions vectorStore = null, CancellationToken cancellationToken = default) + /// A that can be used to wait for + /// the vector store creation to complete. + public virtual CreateVectorStoreOperation CreateVectorStore(bool waitUntilCompleted, VectorStoreCreationOptions vectorStore = null, CancellationToken cancellationToken = default) { using BinaryContent content = vectorStore?.ToBinaryContent(); - ClientResult result = CreateVectorStore(content, cancellationToken.ToRequestOptions()); - return ClientResult.FromValue(VectorStore.FromResponse(result.GetRawResponse()), result.GetRawResponse()); + return CreateVectorStore(waitUntilCompleted, content, cancellationToken.ToRequestOptions()); } /// @@ -216,14 +224,8 @@ public virtual AsyncPageCollection GetVectorStoresAsync( VectorStoreCollectionOptions options = default, CancellationToken cancellationToken = default) { - VectorStoresPageEnumerator enumerator = new(_pipeline, _endpoint, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); + return GetVectorStoresAsync(options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, cancellationToken.ToRequestOptions()) + as AsyncPageCollection; } /// @@ -242,14 +244,8 @@ public virtual AsyncPageCollection GetVectorStoresAsync( Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); VectorStoresPageToken pageToken = VectorStoresPageToken.FromToken(firstPageToken); - VectorStoresPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); + return GetVectorStoresAsync(pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken?.Before, cancellationToken.ToRequestOptions()) + as AsyncPageCollection; } /// @@ -265,14 +261,8 @@ public virtual PageCollection GetVectorStores( VectorStoreCollectionOptions options = default, CancellationToken cancellationToken = default) { - VectorStoresPageEnumerator enumerator = new(_pipeline, _endpoint, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); + return GetVectorStores(options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, cancellationToken.ToRequestOptions()) + as PageCollection; } /// @@ -291,50 +281,52 @@ public virtual PageCollection GetVectorStores( Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); VectorStoresPageToken pageToken = VectorStoresPageToken.FromToken(firstPageToken); - VectorStoresPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); + return GetVectorStores(pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken?.Before, cancellationToken.ToRequestOptions()) + as PageCollection; } /// /// Associates a single, uploaded file with a vector store, beginning ingestion of the file into the vector store. /// + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The ID of the vector store to associate the file with. /// The ID of the file to associate with the vector store. /// A token that can be used to cancel this method call. - /// - /// A instance that represents the new association. - /// - public virtual async Task> AddFileToVectorStoreAsync(string vectorStoreId, string fileId, CancellationToken cancellationToken = default) + /// A that can be used to wait for + /// the vector store file addition to complete. + /// or is null. + public virtual async Task AddFileToVectorStoreAsync(bool waitUntilCompleted, string vectorStoreId, string fileId, CancellationToken cancellationToken = default) { + Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + Argument.AssertNotNullOrEmpty(fileId, nameof(fileId)); + InternalCreateVectorStoreFileRequest internalRequest = new(fileId); - ClientResult protocolResult = await AddFileToVectorStoreAsync(vectorStoreId, internalRequest.ToBinaryContent(), cancellationToken.ToRequestOptions()).ConfigureAwait(false); - PipelineResponse protocolResponse = protocolResult?.GetRawResponse(); - VectorStoreFileAssociation fileAssociation = VectorStoreFileAssociation.FromResponse(protocolResponse); - return ClientResult.FromValue(fileAssociation, protocolResponse); + return await AddFileToVectorStoreAsync(waitUntilCompleted, vectorStoreId, internalRequest.ToBinaryContent(), cancellationToken.ToRequestOptions()).ConfigureAwait(false); } /// /// Associates a single, uploaded file with a vector store, beginning ingestion of the file into the vector store. /// + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The ID of the vector store to associate the file with. /// The ID of the file to associate with the vector store. /// A token that can be used to cancel this method call. - /// - /// A instance that represents the new association. - /// - public virtual ClientResult AddFileToVectorStore(string vectorStoreId, string fileId, CancellationToken cancellationToken = default) + /// A that can be used to wait for + /// the vector store file addition to complete. + /// or is null. + public virtual AddFileToVectorStoreOperation AddFileToVectorStore(bool waitUntilCompleted, string vectorStoreId, string fileId, CancellationToken cancellationToken = default) { + Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + Argument.AssertNotNullOrEmpty(fileId, nameof(fileId)); + InternalCreateVectorStoreFileRequest internalRequest = new(fileId); - ClientResult protocolResult = AddFileToVectorStore(vectorStoreId, internalRequest.ToBinaryContent(), cancellationToken.ToRequestOptions()); - PipelineResponse protocolResponse = protocolResult?.GetRawResponse(); - VectorStoreFileAssociation fileAssociation = VectorStoreFileAssociation.FromResponse(protocolResponse); - return ClientResult.FromValue(fileAssociation, protocolResponse); + return AddFileToVectorStore(waitUntilCompleted, vectorStoreId, internalRequest.ToBinaryContent(), cancellationToken.ToRequestOptions()); } /// @@ -357,16 +349,8 @@ public virtual AsyncPageCollection GetFileAssociatio { Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - VectorStoreFilesPageEnumerator enumerator = new(_pipeline, _endpoint, - vectorStoreId, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - options?.Filter?.ToString(), - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); + return GetFileAssociationsAsync(vectorStoreId, options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, options?.Filter?.ToString(), cancellationToken.ToRequestOptions()) + as AsyncPageCollection; } /// @@ -385,16 +369,8 @@ public virtual AsyncPageCollection GetFileAssociatio Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); VectorStoreFilesPageToken pageToken = VectorStoreFilesPageToken.FromToken(firstPageToken); - VectorStoreFilesPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.VectorStoreId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - pageToken.Filter, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); + return GetFileAssociationsAsync(pageToken?.VectorStoreId, pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken?.Before, pageToken?.Filter, cancellationToken.ToRequestOptions()) + as AsyncPageCollection; } /// @@ -417,16 +393,8 @@ public virtual PageCollection GetFileAssociations( { Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - VectorStoreFilesPageEnumerator enumerator = new(_pipeline, _endpoint, - vectorStoreId, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - options?.Filter?.ToString(), - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); + return GetFileAssociations(vectorStoreId, options?.PageSize, options?.Order?.ToString(), options?.AfterId, options?.BeforeId, options?.Filter?.ToString(), cancellationToken.ToRequestOptions()) + as PageCollection; } /// @@ -445,16 +413,8 @@ public virtual PageCollection GetFileAssociations( Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); VectorStoreFilesPageToken pageToken = VectorStoreFilesPageToken.FromToken(firstPageToken); - VectorStoreFilesPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.VectorStoreId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - pageToken.Filter, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); + return GetFileAssociations(pageToken?.VectorStoreId, pageToken?.Limit, pageToken?.Order, pageToken?.After, pageToken?.Before, pageToken?.Filter, cancellationToken.ToRequestOptions()) + as PageCollection; } /// @@ -540,20 +500,19 @@ public virtual ClientResult RemoveFileFromStore(string vectorStoreId, stri } /// - /// Begins a batch job to associate multiple jobs with a vector store, beginning the ingestion process. + /// Adds multiple files in a batch to the vector store, beginning the ingestion process. /// - /// if the - /// method should return when the service has finished running the - /// operation, or if it should return - /// after the operation has been created but may not have completed - /// processing. + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The ID of the vector store to associate files with. /// The IDs of the files to associate with the vector store. /// A token that can be used to cancel this method call. - /// A that can be used to wait for + /// A that can be used to wait for /// the operation to complete, get information about the batch file job, or cancel the operation. - public virtual async Task CreateBatchFileJobAsync( - ReturnWhen returnWhen, + public virtual async Task CreateBatchFileJobAsync( + bool waitUntilCompleted, string vectorStoreId, IEnumerable fileIds, CancellationToken cancellationToken = default) @@ -564,39 +523,23 @@ public virtual async Task CreateBatchFileJobAsync BinaryContent content = new InternalCreateVectorStoreFileBatchRequest(fileIds).ToBinaryContent(); RequestOptions options = cancellationToken.ToRequestOptions(); - using PipelineMessage message = CreateCreateVectorStoreFileBatchRequest(vectorStoreId, content, options); - PipelineResponse response = await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false); - VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); - - VectorStoreFileBatchOperation operation = new VectorStoreFileBatchOperation( - _pipeline, - _endpoint, - ClientResult.FromValue(value, response)); - - if (returnWhen == ReturnWhen.Started) - { - return operation; - } - - await operation.WaitForCompletionAsync().ConfigureAwait(false); - return operation; + return await CreateBatchFileJobAsync(waitUntilCompleted, vectorStoreId, content, options).ConfigureAwait(false); } /// /// Begins a batch job to associate multiple jobs with a vector store, beginning the ingestion process. /// - /// if the - /// method should return when the service has finished running the - /// operation, or if it should return - /// after the operation has been created but may not have completed - /// processing. + /// Value indicating whether the method + /// should return after the operation has been started and is still running + /// on the service, or wait until the operation has completed to return. + /// /// The ID of the vector store to associate files with. /// The IDs of the files to associate with the vector store. /// A token that can be used to cancel this method call. - /// A that can be used to wait for + /// A that can be used to wait for /// the operation to complete, get information about the batch file job, or cancel the operation. - public virtual VectorStoreFileBatchOperation CreateBatchFileJob( - ReturnWhen returnWhen, + public virtual CreateBatchFileJobOperation CreateBatchFileJob( + bool waitUntilCompleted, string vectorStoreId, IEnumerable fileIds, CancellationToken cancellationToken = default) @@ -607,21 +550,6 @@ public virtual VectorStoreFileBatchOperation CreateBatchFileJob( BinaryContent content = new InternalCreateVectorStoreFileBatchRequest(fileIds).ToBinaryContent(); RequestOptions options = cancellationToken.ToRequestOptions(); - using PipelineMessage message = CreateCreateVectorStoreFileBatchRequest(vectorStoreId, content, options); - PipelineResponse response = _pipeline.ProcessMessage(message, options); - VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); - - VectorStoreFileBatchOperation operation = new VectorStoreFileBatchOperation( - _pipeline, - _endpoint, - ClientResult.FromValue(value, response)); - - if (returnWhen == ReturnWhen.Started) - { - return operation; - } - - operation.WaitForCompletion(); - return operation; + return CreateBatchFileJob(waitUntilCompleted, vectorStoreId, content, options); } } diff --git a/src/Generated/BatchClient.cs b/src/Generated/BatchClient.cs index ff92edef..3ccd2f90 100644 --- a/src/Generated/BatchClient.cs +++ b/src/Generated/BatchClient.cs @@ -81,6 +81,23 @@ internal PipelineMessage CreateRetrieveBatchRequest(string batchId, RequestOptio return message; } + internal PipelineMessage CreateCancelBatchRequest(string batchId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "POST"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/batches/", false); + uri.AppendPath(batchId, true); + uri.AppendPath("/cancel", false); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + private static PipelineMessageClassifier _pipelineMessageClassifier200; private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); } diff --git a/src/Generated/FineTuningClient.cs b/src/Generated/FineTuningClient.cs index 87c48998..7424e033 100644 --- a/src/Generated/FineTuningClient.cs +++ b/src/Generated/FineTuningClient.cs @@ -87,6 +87,73 @@ internal PipelineMessage CreateRetrieveFineTuningJobRequest(string fineTuningJob return message; } + internal PipelineMessage CreateCancelFineTuningJobRequest(string fineTuningJobId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "POST"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + uri.AppendPath("/cancel", false); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateGetFineTuningJobCheckpointsRequest(string fineTuningJobId, string after, int? limit, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + uri.AppendPath("/checkpoints", false); + if (after != null) + { + uri.AppendQuery("after", after, true); + } + if (limit != null) + { + uri.AppendQuery("limit", limit.Value, true); + } + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateGetFineTuningEventsRequest(string fineTuningJobId, string after, int? limit, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/fine_tuning/jobs/", false); + uri.AppendPath(fineTuningJobId, true); + uri.AppendPath("/events", false); + if (after != null) + { + uri.AppendQuery("after", after, true); + } + if (limit != null) + { + uri.AppendQuery("limit", limit.Value, true); + } + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + private static PipelineMessageClassifier _pipelineMessageClassifier200; private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); } diff --git a/src/Generated/VectorStoreClient.cs b/src/Generated/VectorStoreClient.cs index 408d8d30..7b0bcc35 100644 --- a/src/Generated/VectorStoreClient.cs +++ b/src/Generated/VectorStoreClient.cs @@ -31,6 +31,22 @@ internal VectorStoreClient(ClientPipeline pipeline, ApiKeyCredential keyCredenti _endpoint = endpoint; } + public virtual async Task CreateVectorStoreAsync(BinaryContent content, RequestOptions options = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateCreateVectorStoreRequest(content, options); + return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); + } + + public virtual ClientResult CreateVectorStore(BinaryContent content, RequestOptions options = null) + { + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateCreateVectorStoreRequest(content, options); + return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + } + internal PipelineMessage CreateGetVectorStoresRequest(int? limit, string order, string after, string before, RequestOptions options) { var message = _pipeline.CreateMessage(); @@ -258,6 +274,64 @@ internal PipelineMessage CreateGetVectorStoreFileBatchRequest(string vectorStore return message; } + internal PipelineMessage CreateCancelVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "POST"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/vector_stores/", false); + uri.AppendPath(vectorStoreId, true); + uri.AppendPath("/file_batches/", false); + uri.AppendPath(batchId, true); + uri.AppendPath("/cancel", false); + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + + internal PipelineMessage CreateGetFilesInVectorStoreBatchesRequest(string vectorStoreId, string batchId, int? limit, string order, string after, string before, string filter, RequestOptions options) + { + var message = _pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + var request = message.Request; + request.Method = "GET"; + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/vector_stores/", false); + uri.AppendPath(vectorStoreId, true); + uri.AppendPath("/file_batches/", false); + uri.AppendPath(batchId, true); + uri.AppendPath("/files", false); + if (limit != null) + { + uri.AppendQuery("limit", limit.Value, true); + } + if (order != null) + { + uri.AppendQuery("order", order, true); + } + if (after != null) + { + uri.AppendQuery("after", after, true); + } + if (before != null) + { + uri.AppendQuery("before", before, true); + } + if (filter != null) + { + uri.AppendQuery("filter", filter, true); + } + request.Uri = uri.ToUri(); + request.Headers.Set("Accept", "application/json"); + message.Apply(options); + return message; + } + private static PipelineMessageClassifier _pipelineMessageClassifier200; private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); } diff --git a/tests/Assistants/VectorStoreTests.cs b/tests/Assistants/VectorStoreTests.cs index 64073d77..f345a7b0 100644 --- a/tests/Assistants/VectorStoreTests.cs +++ b/tests/Assistants/VectorStoreTests.cs @@ -23,7 +23,8 @@ public void CanCreateGetAndDeleteVectorStores() { VectorStoreClient client = GetTestClient(); - VectorStore vectorStore = client.CreateVectorStore(); + CreateVectorStoreOperation createOperation = client.CreateVectorStore(waitUntilCompleted: false); + VectorStore vectorStore = createOperation.Value; Validate(vectorStore); bool deleted = client.DeleteVectorStore(vectorStore); Assert.That(deleted, Is.True); @@ -31,7 +32,7 @@ public void CanCreateGetAndDeleteVectorStores() IReadOnlyList testFiles = GetNewTestFiles(5); - vectorStore = client.CreateVectorStore(new VectorStoreCreationOptions() + createOperation = client.CreateVectorStore(waitUntilCompleted: false, new VectorStoreCreationOptions() { FileIds = { testFiles[0].Id }, Name = "test vector store", @@ -45,19 +46,21 @@ public void CanCreateGetAndDeleteVectorStores() ["test-key"] = "test-value", }, }); - Validate(vectorStore); + Validate(createOperation.Value); + Assert.Multiple(() => { - Assert.That(vectorStore.Name, Is.EqualTo("test vector store")); - Assert.That(vectorStore.ExpirationPolicy?.Anchor, Is.EqualTo(VectorStoreExpirationAnchor.LastActiveAt)); - Assert.That(vectorStore.ExpirationPolicy?.Days, Is.EqualTo(3)); - Assert.That(vectorStore.FileCounts.Total, Is.EqualTo(1)); - Assert.That(vectorStore.CreatedAt, Is.GreaterThan(s_2024)); - Assert.That(vectorStore.ExpiresAt, Is.GreaterThan(s_2024)); - Assert.That(vectorStore.Status, Is.EqualTo(VectorStoreStatus.InProgress)); - Assert.That(vectorStore.Metadata?.TryGetValue("test-key", out string metadataValue) == true && metadataValue == "test-value"); + Assert.That(createOperation.Value.Name, Is.EqualTo("test vector store")); + Assert.That(createOperation.Value.ExpirationPolicy?.Anchor, Is.EqualTo(VectorStoreExpirationAnchor.LastActiveAt)); + Assert.That(createOperation.Value.ExpirationPolicy?.Days, Is.EqualTo(3)); + Assert.That(createOperation.Value.FileCounts.Total, Is.EqualTo(1)); + Assert.That(createOperation.Value.CreatedAt, Is.GreaterThan(s_2024)); + Assert.That(createOperation.Value.ExpiresAt, Is.GreaterThan(s_2024)); + Assert.That(createOperation.Status, Is.EqualTo(VectorStoreStatus.InProgress)); + Assert.That(createOperation.Value.Metadata?.TryGetValue("test-key", out string metadataValue) == true && metadataValue == "test-value"); }); - vectorStore = client.GetVectorStore(vectorStore); + + vectorStore = createOperation.Value; Assert.Multiple(() => { Assert.That(vectorStore.Name, Is.EqualTo("test vector store")); @@ -73,10 +76,11 @@ public void CanCreateGetAndDeleteVectorStores() Assert.That(deleted, Is.True); _vectorStoresToDelete.RemoveAt(_vectorStoresToDelete.Count - 1); - vectorStore = client.CreateVectorStore(new VectorStoreCreationOptions() + createOperation = client.CreateVectorStore(waitUntilCompleted: false, new VectorStoreCreationOptions() { FileIds = testFiles.Select(file => file.Id).ToList() }); + vectorStore = createOperation.Value; Validate(vectorStore); Assert.Multiple(() => { @@ -91,10 +95,11 @@ public void CanEnumerateVectorStores() VectorStoreClient client = GetTestClient(); for (int i = 0; i < 10; i++) { - VectorStore vectorStore = client.CreateVectorStore(new VectorStoreCreationOptions() + CreateVectorStoreOperation createOperation = client.CreateVectorStore(waitUntilCompleted: true, new VectorStoreCreationOptions() { Name = $"Test Vector Store {i}", }); + VectorStore vectorStore = createOperation.Value; Validate(vectorStore); Assert.That(vectorStore.Name, Is.EqualTo($"Test Vector Store {i}")); } @@ -128,11 +133,14 @@ public async Task CanEnumerateVectorStoresAsync() VectorStoreClient client = GetTestClient(); for (int i = 0; i < 10; i++) { - VectorStore vectorStore = await client.CreateVectorStoreAsync(new VectorStoreCreationOptions() - { - Name = $"Test Vector Store {i}", - }); + CreateVectorStoreOperation createOperation = await client.CreateVectorStoreAsync(waitUntilCompleted: true, + new VectorStoreCreationOptions() + { + Name = $"Test Vector Store {i}", + }); + VectorStore vectorStore = createOperation.Value; Validate(vectorStore); + Assert.That(vectorStore.Name, Is.EqualTo($"Test Vector Store {i}")); } @@ -163,14 +171,16 @@ public async Task CanEnumerateVectorStoresAsync() public void CanAssociateFiles() { VectorStoreClient client = GetTestClient(); - VectorStore vectorStore = client.CreateVectorStore(); + CreateVectorStoreOperation createOperation = client.CreateVectorStore(waitUntilCompleted: true); + VectorStore vectorStore = createOperation.Value; Validate(vectorStore); IReadOnlyList files = GetNewTestFiles(3); foreach (OpenAIFileInfo file in files) { - VectorStoreFileAssociation association = client.AddFileToVectorStore(vectorStore, file); + AddFileToVectorStoreOperation addOperation = client.AddFileToVectorStore(waitUntilCompleted: false, vectorStore, file); + VectorStoreFileAssociation association = addOperation.Value; Validate(association); Assert.Multiple(() => { @@ -203,14 +213,16 @@ public void CanAssociateFiles() public void Pagination_CanRehydrateFileAssociationCollection() { VectorStoreClient client = GetTestClient(); - VectorStore vectorStore = client.CreateVectorStore(); + CreateVectorStoreOperation createOperation = client.CreateVectorStore(waitUntilCompleted: true); + VectorStore vectorStore = createOperation.Value; Validate(vectorStore); IReadOnlyList files = GetNewTestFiles(3); foreach (OpenAIFileInfo file in files) { - VectorStoreFileAssociation association = client.AddFileToVectorStore(vectorStore, file); + AddFileToVectorStoreOperation addOperation = client.AddFileToVectorStore(waitUntilCompleted: false, vectorStore, file); + VectorStoreFileAssociation association = addOperation.Value; Validate(association); Assert.Multiple(() => { @@ -266,12 +278,13 @@ public void Pagination_CanRehydrateFileAssociationCollection() public void CanUseBatchIngestion() { VectorStoreClient client = GetTestClient(); - VectorStore vectorStore = client.CreateVectorStore(); + CreateVectorStoreOperation createOperation = client.CreateVectorStore(waitUntilCompleted: true); + VectorStore vectorStore = createOperation.Value; Validate(vectorStore); IReadOnlyList testFiles = GetNewTestFiles(5); - VectorStoreFileBatchOperation batchOperation = client.CreateBatchFileJob(ReturnWhen.Started, vectorStore, testFiles); + CreateBatchFileJobOperation batchOperation = client.CreateBatchFileJob(waitUntilCompleted: false, vectorStore, testFiles); Validate(batchOperation); Assert.Multiple(() => @@ -283,7 +296,7 @@ public void CanUseBatchIngestion() batchOperation.WaitForCompletion(); - foreach (VectorStoreFileAssociation association in batchOperation.GetFileAssociations().GetAllValues()) + foreach (VectorStoreFileAssociation association in batchOperation.GetFilesInBatch().GetAllValues()) { Assert.Multiple(() => { @@ -301,19 +314,20 @@ public void CanUseBatchIngestion() public void CanRehydrateBatchFileJob() { VectorStoreClient client = GetTestClient(); - VectorStore vectorStore = client.CreateVectorStore(); + CreateVectorStoreOperation createOperation = client.CreateVectorStore(waitUntilCompleted: true); + VectorStore vectorStore = createOperation.Value; Validate(vectorStore); IReadOnlyList testFiles = GetNewTestFiles(5); - VectorStoreFileBatchOperation batchOperation = client.CreateBatchFileJob(ReturnWhen.Started, vectorStore, testFiles); + CreateBatchFileJobOperation batchOperation = client.CreateBatchFileJob(waitUntilCompleted: false, vectorStore, testFiles); Validate(batchOperation); - // Simulate rehydration of the collection + // Simulate rehydration of the operation BinaryData rehydrationBytes = batchOperation.RehydrationToken.ToBytes(); ContinuationToken rehydrationToken = ContinuationToken.FromBytes(rehydrationBytes); - VectorStoreFileBatchOperation rehydratedOperation = VectorStoreFileBatchOperation.Rehydrate(client, rehydrationToken); + CreateBatchFileJobOperation rehydratedOperation = CreateBatchFileJobOperation.Rehydrate(client, rehydrationToken); Validate(rehydratedOperation); Assert.Multiple(() => @@ -360,11 +374,12 @@ public async Task CanApplyChunkingStrategy(ChunkingStrategyKind strategyKind) Assert.That(inputStaticStrategy.OverlappingTokenCount, Is.EqualTo(250)); } - VectorStore vectorStore = await client.CreateVectorStoreAsync(new VectorStoreCreationOptions() + CreateVectorStoreOperation createOperation = await client.CreateVectorStoreAsync(waitUntilCompleted: true, new VectorStoreCreationOptions() { FileIds = testFiles.Select(file => file.Id).ToList(), ChunkingStrategy = chunkingStrategy, }); + VectorStore vectorStore = createOperation.Value; Validate(vectorStore); Assert.That(vectorStore.FileCounts.Total, Is.EqualTo(5)); @@ -418,9 +433,9 @@ protected void Cleanup() { ErrorOptions = ClientErrorBehaviors.NoThrow, }; - foreach (VectorStoreFileBatchOperation job in _jobsToCancel) + foreach (CreateBatchFileJobOperation job in _jobsToCancel) { - ClientResult protocolResult = job.CancelBatchFileJob(job.VectorStoreId, job.BatchId, requestOptions); + ClientResult protocolResult = job.CancelFileBatch(requestOptions); Console.WriteLine($"Cleanup: {job.BatchId} => {protocolResult?.GetRawResponse()?.Status}"); } foreach (VectorStoreFileAssociation association in _associationsToRemove) @@ -449,7 +464,7 @@ protected void Cleanup() /// The provided instance type isn't supported. private void Validate(T target) { - if (target is VectorStoreFileBatchOperation job) + if (target is CreateBatchFileJobOperation job) { Assert.That(job.BatchId, Is.Not.Null); _jobsToCancel.Add(job); @@ -476,7 +491,7 @@ private void Validate(T target) } } - private readonly List _jobsToCancel = []; + private readonly List _jobsToCancel = []; private readonly List _associationsToRemove = []; private readonly List _filesToDelete = []; private readonly List _vectorStoresToDelete = []; diff --git a/tests/Batch/BatchTests.cs b/tests/Batch/BatchTests.cs index 1289d74a..de8b8c2a 100644 --- a/tests/Batch/BatchTests.cs +++ b/tests/Batch/BatchTests.cs @@ -54,7 +54,7 @@ public async Task ListBatchesProtocol() public async Task CreateGetAndCancelBatchProtocol() { using MemoryStream testFileStream = new(); - using StreamWriter streamWriter = new (testFileStream); + using StreamWriter streamWriter = new(testFileStream); string input = @"{""custom_id"": ""request-1"", ""method"": ""POST"", ""url"": ""/v1/chat/completions"", ""body"": {""model"": ""gpt-4o-mini"", ""messages"": [{""role"": ""system"", ""content"": ""You are a helpful assistant.""}, {""role"": ""user"", ""content"": ""What is 2+2?""}]}}"; streamWriter.WriteLine(input); streamWriter.Flush(); @@ -75,9 +75,9 @@ public async Task CreateGetAndCancelBatchProtocol() testMetadataKey = "test metadata value", }, })); - BatchOperation batchOperation = IsAsync - ? await client.CreateBatchAsync(ReturnWhen.Started, content) - : client.CreateBatch(ReturnWhen.Started, content); + CreateBatchOperation batchOperation = IsAsync + ? await client.CreateBatchAsync(waitUntilCompleted: false, content) + : client.CreateBatch(waitUntilCompleted: false, content); BinaryData response = batchOperation.GetRawResponse().Content; JsonDocument jsonDocument = JsonDocument.Parse(response); @@ -106,8 +106,8 @@ public async Task CreateGetAndCancelBatchProtocol() Assert.That(endpoint, Is.EqualTo("/v1/chat/completions")); ClientResult clientResult = IsAsync - ? await batchOperation.CancelBatchAsync(id, options: null) - : batchOperation.CancelBatch(id, options: null); + ? await batchOperation.CancelBatchAsync(options: null) + : batchOperation.CancelBatch(options: null); statusElement = jsonDocument.RootElement.GetProperty("status"); status = statusElement.GetString(); @@ -127,5 +127,79 @@ public async Task CreateGetAndCancelBatchProtocol() //Assert.That(newBatchDynamic.status, Is.EqualTo("cancelling")); } + [Test] + public async Task CanRehydrateBatchOperation() + { + using MemoryStream testFileStream = new(); + using StreamWriter streamWriter = new(testFileStream); + string input = @"{""custom_id"": ""request-1"", ""method"": ""POST"", ""url"": ""/v1/chat/completions"", ""body"": {""model"": ""gpt-4o-mini"", ""messages"": [{""role"": ""system"", ""content"": ""You are a helpful assistant.""}, {""role"": ""user"", ""content"": ""What is 2+2?""}]}}"; + streamWriter.WriteLine(input); + streamWriter.Flush(); + testFileStream.Position = 0; + + FileClient fileClient = new(); + OpenAIFileInfo inputFile = await fileClient.UploadFileAsync(testFileStream, "test-batch-file", FileUploadPurpose.Batch); + Assert.That(inputFile.Id, Is.Not.Null.And.Not.Empty); + + BatchClient client = GetTestClient(); + BinaryContent content = BinaryContent.Create(BinaryData.FromObjectAsJson(new + { + input_file_id = inputFile.Id, + endpoint = "/v1/chat/completions", + completion_window = "24h", + metadata = new + { + testMetadataKey = "test metadata value", + }, + })); + CreateBatchOperation batchOperation = IsAsync + ? await client.CreateBatchAsync(waitUntilCompleted: false, content) + : client.CreateBatch(waitUntilCompleted: false, content); + + // Simulate rehydration of the operation + BinaryData rehydrationBytes = batchOperation.RehydrationToken.ToBytes(); + ContinuationToken rehydrationToken = ContinuationToken.FromBytes(rehydrationBytes); + + CreateBatchOperation rehydratedOperation = IsAsync ? + await CreateBatchOperation.RehydrateAsync(client, rehydrationToken) : + CreateBatchOperation.Rehydrate(client, rehydrationToken); + + static bool Validate(CreateBatchOperation operation) + { + BinaryData response = operation.GetRawResponse().Content; + JsonDocument jsonDocument = JsonDocument.Parse(response); + + JsonElement idElement = jsonDocument.RootElement.GetProperty("id"); + JsonElement createdAtElement = jsonDocument.RootElement.GetProperty("created_at"); + JsonElement statusElement = jsonDocument.RootElement.GetProperty("status"); + JsonElement metadataElement = jsonDocument.RootElement.GetProperty("metadata"); + JsonElement testMetadataKeyElement = metadataElement.GetProperty("testMetadataKey"); + + string id = idElement.GetString(); + long createdAt = createdAtElement.GetInt64(); + string status = statusElement.GetString(); + string testMetadataKey = testMetadataKeyElement.GetString(); + + long unixTime2024 = (new DateTimeOffset(2024, 01, 01, 0, 0, 0, TimeSpan.Zero)).ToUnixTimeSeconds(); + + Assert.That(id, Is.Not.Null.And.Not.Empty); + Assert.That(createdAt, Is.GreaterThan(unixTime2024)); + Assert.That(status, Is.EqualTo("validating")); + Assert.That(testMetadataKey, Is.EqualTo("test metadata value")); + + return true; + } + + Assert.IsTrue(Validate(batchOperation)); + Assert.IsTrue(Validate(rehydratedOperation)); + + Task.WaitAll( + IsAsync ? batchOperation.WaitForCompletionAsync() : Task.Run(() => batchOperation.WaitForCompletion()), + IsAsync ? rehydratedOperation.WaitForCompletionAsync() : Task.Run(() => rehydratedOperation.WaitForCompletion())); + + Assert.IsTrue(batchOperation.IsCompleted); + Assert.IsTrue(rehydratedOperation.IsCompleted); + } + private static BatchClient GetTestClient() => GetTestClient(TestScenario.Batch); } \ No newline at end of file diff --git a/tests/FineTuning/FineTuningTests.cs b/tests/FineTuning/FineTuningTests.cs index cf6d4d0d..93ed3e98 100644 --- a/tests/FineTuning/FineTuningTests.cs +++ b/tests/FineTuning/FineTuningTests.cs @@ -9,13 +9,12 @@ namespace OpenAI.Tests.FineTuning; -#pragma warning disable OPENAI001 - [Parallelizable(ParallelScope.Fixtures)] +[Category("FineTuning")] public partial class FineTuningTests { [Test] - public void BasicFineTuningOperationsWork() + public void BasicFineTuningJobOperationsWork() { // Upload training file first FileClient fileClient = GetTestClient(TestScenario.Files); @@ -34,7 +33,7 @@ public void BasicFineTuningOperationsWork() BinaryData input = BinaryData.FromString(json); using BinaryContent content = BinaryContent.Create(input); - FineTuningOperation operation = client.CreateJob(ReturnWhen.Started, content); + CreateJobOperation operation = client.CreateJob(waitUntilCompleted: false, content); } [OneTimeTearDown] @@ -85,5 +84,3 @@ private void Validate(T target) private static readonly DateTimeOffset s_2024 = new(2024, 1, 1, 0, 0, 0, TimeSpan.Zero); private static readonly string s_cleanupMetadataKey = $"test_metadata_cleanup_eligible"; } - -#pragma warning restore OPENAI001 From 9c80fde148feebe79bf7c88eef8287dec99ed723 Mon Sep 17 00:00:00 2001 From: Anne Thompson Date: Fri, 9 Aug 2024 09:23:39 -0700 Subject: [PATCH 14/14] remove unused files --- src/Custom/Batch/BatchOperation.Protocol.cs | 285 ------------ src/Custom/Batch/BatchOperationToken.cs | 90 ---- .../FineTuningOperation.Protocol.cs | 430 ------------------ .../FineTuning/FineTuningOperationToken.cs | 91 ---- .../VectorStoreFileBatchOperation.Protocol.cs | 269 ----------- .../VectorStoreFileBatchOperation.cs | 381 ---------------- .../VectorStoreFileBatchOperationToken.cs | 101 ---- 7 files changed, 1647 deletions(-) delete mode 100644 src/Custom/Batch/BatchOperation.Protocol.cs delete mode 100644 src/Custom/Batch/BatchOperationToken.cs delete mode 100644 src/Custom/FineTuning/FineTuningOperation.Protocol.cs delete mode 100644 src/Custom/FineTuning/FineTuningOperationToken.cs delete mode 100644 src/Custom/VectorStores/VectorStoreFileBatchOperation.Protocol.cs delete mode 100644 src/Custom/VectorStores/VectorStoreFileBatchOperation.cs delete mode 100644 src/Custom/VectorStores/VectorStoreFileBatchOperationToken.cs diff --git a/src/Custom/Batch/BatchOperation.Protocol.cs b/src/Custom/Batch/BatchOperation.Protocol.cs deleted file mode 100644 index d1198765..00000000 --- a/src/Custom/Batch/BatchOperation.Protocol.cs +++ /dev/null @@ -1,285 +0,0 @@ -using System; -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -#nullable enable - -namespace OpenAI.Batch; - -/// -/// A long-running operation for executing a batch from an uploaded file of -/// requests. -/// -public partial class BatchOperation : OperationResult -{ - private readonly ClientPipeline _pipeline; - private readonly Uri _endpoint; - - private readonly string _batchId; - - private PollingInterval? _pollingInterval; - - internal BatchOperation( - ClientPipeline pipeline, - Uri endpoint, - string batchId, - string status, - PipelineResponse response) - : base(response) - { - _pipeline = pipeline; - _endpoint = endpoint; - _batchId = batchId; - - IsCompleted = GetIsCompleted(status); - RehydrationToken = new BatchOperationToken(batchId); - } - - /// - public override ContinuationToken? RehydrationToken { get; protected set; } - - /// - public override bool IsCompleted { get; protected set; } - - /// - /// Recreates a from a rehydration token. - /// - /// The used to obtain the - /// operation status from the service. - /// The rehydration token corresponding to - /// the operation to rehydrate. - /// A token that can be used to cancel the - /// request. - /// The rehydrated operation. - public static async Task RehydrateAsync(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(client, nameof(client)); - Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); - - BatchOperationToken token = BatchOperationToken.FromToken(rehydrationToken); - - ClientResult result = await client.GetBatchAsync(token.BatchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - PipelineResponse response = result.GetRawResponse(); - - using JsonDocument doc = JsonDocument.Parse(response.Content); - string status = doc.RootElement.GetProperty("status"u8).GetString()!; - - return new BatchOperation(client.Pipeline, client.Endpoint, token.BatchId, status, response); - } - - /// - /// Recreates a from a rehydration token. - /// - /// The used to obtain the - /// operation status from the service. - /// The rehydration token corresponding to - /// the operation to rehydrate. - /// A token that can be used to cancel the - /// request. - /// The rehydrated operation. - public static BatchOperation Rehydrate(BatchClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(client, nameof(client)); - Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); - - BatchOperationToken token = BatchOperationToken.FromToken(rehydrationToken); - - ClientResult result = client.GetBatch(token.BatchId, cancellationToken.ToRequestOptions()); - PipelineResponse response = result.GetRawResponse(); - - using JsonDocument doc = JsonDocument.Parse(response.Content); - string status = doc.RootElement.GetProperty("status"u8).GetString()!; - - return new BatchOperation(client.Pipeline, client.Endpoint, token.BatchId, status, response); - } - - /// - public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) - { - _pollingInterval ??= new(); - - while (!IsCompleted) - { - PipelineResponse response = GetRawResponse(); - - await _pollingInterval.WaitAsync(response, cancellationToken); - - ClientResult result = await GetBatchAsync(_batchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - - ApplyUpdate(result); - } - } - - /// - /// Waits for the operation to complete processing on the service. - /// - /// The time to wait between sending requests - /// for status updates from the service. - /// A token that can be used to cancel this - /// method call. - public async Task WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken = default) - { - _pollingInterval = new(pollingInterval); - - await WaitForCompletionAsync(cancellationToken).ConfigureAwait(false); - } - - /// - public override void WaitForCompletion(CancellationToken cancellationToken = default) - { - _pollingInterval ??= new(); - - while (!IsCompleted) - { - PipelineResponse response = GetRawResponse(); - - _pollingInterval.Wait(response, cancellationToken); - - ClientResult result = GetBatch(_batchId, cancellationToken.ToRequestOptions()); - - ApplyUpdate(result); - } - } - - /// - /// Waits for the operation to complete processing on the service. - /// - /// The time to wait between sending requests - /// for status updates from the service. - /// A token that can be used to cancel this - /// method call. - public void WaitForCompletion(TimeSpan pollingInterval, CancellationToken cancellationToken = default) - { - _pollingInterval = new(pollingInterval); - - WaitForCompletion(cancellationToken); - } - - private void ApplyUpdate(ClientResult result) - { - PipelineResponse response = result.GetRawResponse(); - - using JsonDocument doc = JsonDocument.Parse(response.Content); - string? status = doc.RootElement.GetProperty("status"u8).GetString(); - - IsCompleted = GetIsCompleted(status); - SetRawResponse(response); - } - - private static bool GetIsCompleted(string? status) - { - return status == "completed" || - status == "cancelled" || - status == "expired" || - status == "failed"; - } - - // Generated protocol methods - - /// - /// [Protocol Method] Retrieves a batch. - /// - /// The ID of the batch to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task GetBatchAsync(string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateRetrieveBatchRequest(batchId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Retrieves a batch. - /// - /// The ID of the batch to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult GetBatch(string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateRetrieveBatchRequest(batchId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - /// - /// [Protocol Method] Cancels an in-progress batch. - /// - /// The ID of the batch to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task CancelBatchAsync(string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateCancelBatchRequest(batchId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Cancels an in-progress batch. - /// - /// The ID of the batch to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult CancelBatch(string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateCancelBatchRequest(batchId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - internal PipelineMessage CreateRetrieveBatchRequest(string batchId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/batches/", false); - uri.AppendPath(batchId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateCancelBatchRequest(string batchId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "POST"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/batches/", false); - uri.AppendPath(batchId, true); - uri.AppendPath("/cancel", false); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - private static PipelineMessageClassifier? _pipelineMessageClassifier200; - private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); -} \ No newline at end of file diff --git a/src/Custom/Batch/BatchOperationToken.cs b/src/Custom/Batch/BatchOperationToken.cs deleted file mode 100644 index 41b3b9a1..00000000 --- a/src/Custom/Batch/BatchOperationToken.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.ClientModel; -using System.Diagnostics; -using System.IO; -using System.Text.Json; - -#nullable enable - -namespace OpenAI.Batch; - -internal class BatchOperationToken : ContinuationToken -{ - public BatchOperationToken(string batchId) - { - BatchId = batchId; - } - - public string BatchId { get; } - - public override BinaryData ToBytes() - { - using MemoryStream stream = new(); - using Utf8JsonWriter writer = new(stream); - writer.WriteStartObject(); - - writer.WriteString("batchId", BatchId); - - writer.WriteEndObject(); - - writer.Flush(); - stream.Position = 0; - - return BinaryData.FromStream(stream); - } - - public static BatchOperationToken FromToken(ContinuationToken continuationToken) - { - if (continuationToken is BatchOperationToken token) - { - return token; - } - - BinaryData data = continuationToken.ToBytes(); - - if (data.ToMemory().Length == 0) - { - throw new ArgumentException("Failed to create BatchOperationToken from provided continuationToken.", nameof(continuationToken)); - } - - Utf8JsonReader reader = new(data); - - string batchId = null!; - - reader.Read(); - - Debug.Assert(reader.TokenType == JsonTokenType.StartObject); - - while (reader.Read()) - { - if (reader.TokenType == JsonTokenType.EndObject) - { - break; - } - - Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); - - string propertyName = reader.GetString()!; - - switch (propertyName) - { - case "batchId": - reader.Read(); - Debug.Assert(reader.TokenType == JsonTokenType.String); - batchId = reader.GetString()!; - break; - - default: - throw new JsonException($"Unrecognized property '{propertyName}'."); - } - } - - if (batchId is null) - { - throw new ArgumentException("Failed to create BatchOperationToken from provided continuationToken.", nameof(continuationToken)); - } - - return new(batchId); - } -} - diff --git a/src/Custom/FineTuning/FineTuningOperation.Protocol.cs b/src/Custom/FineTuning/FineTuningOperation.Protocol.cs deleted file mode 100644 index eb7b4826..00000000 --- a/src/Custom/FineTuning/FineTuningOperation.Protocol.cs +++ /dev/null @@ -1,430 +0,0 @@ -using System; -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; - -#nullable enable - -namespace OpenAI.FineTuning; - -/// -/// A long-running operation for creating a new model from a given dataset. -/// -public partial class FineTuningOperation : OperationResult -{ - private readonly ClientPipeline _pipeline; - private readonly Uri _endpoint; - - private readonly string _jobId; - - private PollingInterval? _pollingInterval; - - internal FineTuningOperation( - ClientPipeline pipeline, - Uri endpoint, - string jobId, - string status, - PipelineResponse response) : base(response) - { - _pipeline = pipeline; - _endpoint = endpoint; - _jobId = jobId; - - IsCompleted = GetIsCompleted(status); - RehydrationToken = new FineTuningOperationToken(jobId); - } - - /// - public override ContinuationToken? RehydrationToken { get; protected set; } - - /// - public override bool IsCompleted { get; protected set; } - - /// - /// Recreates a from a rehydration token. - /// - /// The used to obtain the - /// operation status from the service. - /// The rehydration token corresponding to - /// the operation to rehydrate. - /// A token that can be used to cancel the - /// request. - /// The rehydrated operation. - public static async Task RehydrateAsync(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(client, nameof(client)); - Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); - - FineTuningOperationToken token = FineTuningOperationToken.FromToken(rehydrationToken); - - ClientResult result = await client.GetJobAsync(token.JobId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - PipelineResponse response = result.GetRawResponse(); - - using JsonDocument doc = JsonDocument.Parse(response.Content); - string status = doc.RootElement.GetProperty("status"u8).GetString()!; - - return new FineTuningOperation(client.Pipeline, client.Endpoint, token.JobId, status, response); - } - - /// - /// Recreates a from a rehydration token. - /// - /// The used to obtain the - /// operation status from the service. - /// The rehydration token corresponding to - /// the operation to rehydrate. - /// A token that can be used to cancel the - /// request. - /// The rehydrated operation. - public static FineTuningOperation Rehydrate(FineTuningClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(client, nameof(client)); - Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); - - FineTuningOperationToken token = FineTuningOperationToken.FromToken(rehydrationToken); - - ClientResult result = client.GetJob(token.JobId, cancellationToken.ToRequestOptions()); - PipelineResponse response = result.GetRawResponse(); - - using JsonDocument doc = JsonDocument.Parse(response.Content); - string status = doc.RootElement.GetProperty("status"u8).GetString()!; - - return new FineTuningOperation(client.Pipeline, client.Endpoint, token.JobId, status, response); - } - - /// - public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) - { - _pollingInterval ??= new(); - - while (!IsCompleted) - { - PipelineResponse response = GetRawResponse(); - - await _pollingInterval.WaitAsync(response, cancellationToken); - - ClientResult result = await GetJobAsync(_jobId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - - ApplyUpdate(result); - } - } - - /// - /// Waits for the operation to complete processing on the service. - /// - /// The time to wait between sending requests - /// for status updates from the service. - /// A token that can be used to cancel this - /// method call. - public async Task WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken = default) - { - _pollingInterval = new(pollingInterval); - - await WaitForCompletionAsync(cancellationToken).ConfigureAwait(false); - } - - /// - public override void WaitForCompletion(CancellationToken cancellationToken = default) - { - _pollingInterval ??= new(); - - while (!IsCompleted) - { - PipelineResponse response = GetRawResponse(); - - _pollingInterval.Wait(response, cancellationToken); - - ClientResult result = GetJob(_jobId, cancellationToken.ToRequestOptions()); - - ApplyUpdate(result); - } - } - - /// - /// Waits for the operation to complete processing on the service. - /// - /// The time to wait between sending requests - /// for status updates from the service. - /// A token that can be used to cancel this - /// method call. - public void WaitForCompletion(TimeSpan pollingInterval, CancellationToken cancellationToken = default) - { - _pollingInterval = new(pollingInterval); - - WaitForCompletion(cancellationToken); - } - - private void ApplyUpdate(ClientResult result) - { - PipelineResponse response = result.GetRawResponse(); - - using JsonDocument doc = JsonDocument.Parse(response.Content); - string? status = doc.RootElement.GetProperty("status"u8).GetString(); - - IsCompleted = GetIsCompleted(status); - SetRawResponse(response); - } - - private static bool GetIsCompleted(string? status) - { - return status == "succeeded" || - status == "failed" || - status == "cancelled"; - } - - // Generated protocol methods - - // CUSTOM: - // - Renamed. - // - Edited doc comment. - /// - /// [Protocol Method] Get info about a fine-tuning job. - /// - /// [Learn more about fine-tuning](/docs/guides/fine-tuning) - /// - /// The ID of the fine-tuning job. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task GetJobAsync(string jobId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateRetrieveFineTuningJobRequest(jobId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - // CUSTOM: - // - Renamed. - // - Edited doc comment. - /// - /// [Protocol Method] Get info about a fine-tuning job. - /// - /// [Learn more about fine-tuning](/docs/guides/fine-tuning) - /// - /// The ID of the fine-tuning job. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult GetJob(string jobId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateRetrieveFineTuningJobRequest(jobId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - // CUSTOM: - // - Renamed. - // - Edited doc comment. - /// - /// [Protocol Method] Immediately cancel a fine-tune job. - /// - /// The ID of the fine-tuning job to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task CancelJobAsync(string jobId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateCancelFineTuningJobRequest(jobId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - // CUSTOM: - // - Renamed. - // - Edited doc comment. - /// - /// [Protocol Method] Immediately cancel a fine-tune job. - /// - /// The ID of the fine-tuning job to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult CancelJob(string jobId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateCancelFineTuningJobRequest(jobId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - // CUSTOM: - // - Renamed. - // - Edited doc comment. - /// - /// [Protocol Method] Get status updates for a fine-tuning job. - /// - /// The ID of the fine-tuning job to get events for. - /// Identifier for the last event from the previous pagination request. - /// Number of events to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task GetJobEventsAsync(string jobId, string after, int? limit, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateGetFineTuningEventsRequest(jobId, after, limit, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - // CUSTOM: - // - Renamed. - // - Edited doc comment. - /// - /// [Protocol Method] Get status updates for a fine-tuning job. - /// - /// The ID of the fine-tuning job to get events for. - /// Identifier for the last event from the previous pagination request. - /// Number of events to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult GetJobEvents(string jobId, string after, int? limit, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(jobId, nameof(jobId)); - - using PipelineMessage message = CreateGetFineTuningEventsRequest(jobId, after, limit, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - /// - /// [Protocol Method] List the checkpoints for a fine-tuning job. - /// - /// The ID of the fine-tuning job to get checkpoints for. - /// Identifier for the last checkpoint ID from the previous pagination request. - /// Number of checkpoints to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual async Task GetJobCheckpointsAsync(string fineTuningJobId, string after, int? limit, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(fineTuningJobId, nameof(fineTuningJobId)); - - using PipelineMessage message = CreateGetFineTuningJobCheckpointsRequest(fineTuningJobId, after, limit, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] List the checkpoints for a fine-tuning job. - /// - /// The ID of the fine-tuning job to get checkpoints for. - /// Identifier for the last checkpoint ID from the previous pagination request. - /// Number of checkpoints to retrieve. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// is null. - /// is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - public virtual ClientResult GetJobCheckpoints(string fineTuningJobId, string after, int? limit, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(fineTuningJobId, nameof(fineTuningJobId)); - - using PipelineMessage message = CreateGetFineTuningJobCheckpointsRequest(fineTuningJobId, after, limit, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - internal PipelineMessage CreateRetrieveFineTuningJobRequest(string fineTuningJobId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/fine_tuning/jobs/", false); - uri.AppendPath(fineTuningJobId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateCancelFineTuningJobRequest(string fineTuningJobId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "POST"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/fine_tuning/jobs/", false); - uri.AppendPath(fineTuningJobId, true); - uri.AppendPath("/cancel", false); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateGetFineTuningJobCheckpointsRequest(string fineTuningJobId, string after, int? limit, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/fine_tuning/jobs/", false); - uri.AppendPath(fineTuningJobId, true); - uri.AppendPath("/checkpoints", false); - if (after != null) - { - uri.AppendQuery("after", after, true); - } - if (limit != null) - { - uri.AppendQuery("limit", limit.Value, true); - } - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateGetFineTuningEventsRequest(string fineTuningJobId, string after, int? limit, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/fine_tuning/jobs/", false); - uri.AppendPath(fineTuningJobId, true); - uri.AppendPath("/events", false); - if (after != null) - { - uri.AppendQuery("after", after, true); - } - if (limit != null) - { - uri.AppendQuery("limit", limit.Value, true); - } - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - private static PipelineMessageClassifier? _pipelineMessageClassifier200; - private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); -} diff --git a/src/Custom/FineTuning/FineTuningOperationToken.cs b/src/Custom/FineTuning/FineTuningOperationToken.cs deleted file mode 100644 index a2f131d3..00000000 --- a/src/Custom/FineTuning/FineTuningOperationToken.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.ClientModel; -using System.Diagnostics; -using System.IO; -using System.Text.Json; - -#nullable enable - -namespace OpenAI.FineTuning; - -internal class FineTuningOperationToken : ContinuationToken -{ - public FineTuningOperationToken(string jobId) - { - JobId = jobId; - } - - public string JobId { get; } - - public override BinaryData ToBytes() - { - using MemoryStream stream = new(); - using Utf8JsonWriter writer = new(stream); - - writer.WriteStartObject(); - - writer.WriteString("jobId", JobId); - - writer.WriteEndObject(); - - writer.Flush(); - stream.Position = 0; - - return BinaryData.FromStream(stream); - } - - public static FineTuningOperationToken FromToken(ContinuationToken continuationToken) - { - if (continuationToken is FineTuningOperationToken token) - { - return token; - } - - BinaryData data = continuationToken.ToBytes(); - - if (data.ToMemory().Length == 0) - { - throw new ArgumentException("Failed to create FineTuningOperationToken from provided continuationToken.", nameof(continuationToken)); - } - - Utf8JsonReader reader = new(data); - - string jobId = null!; - - reader.Read(); - - Debug.Assert(reader.TokenType == JsonTokenType.StartObject); - - while (reader.Read()) - { - if (reader.TokenType == JsonTokenType.EndObject) - { - break; - } - - Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); - - string propertyName = reader.GetString()!; - - switch (propertyName) - { - case "jobId": - reader.Read(); - Debug.Assert(reader.TokenType == JsonTokenType.String); - jobId = reader.GetString()!; - break; - - default: - throw new JsonException($"Unrecognized property '{propertyName}'."); - } - } - - if (jobId is null) - { - throw new ArgumentException("Failed to create RunOperationToken from provided continuationToken.", nameof(continuationToken)); - } - - return new(jobId); - } -} - diff --git a/src/Custom/VectorStores/VectorStoreFileBatchOperation.Protocol.cs b/src/Custom/VectorStores/VectorStoreFileBatchOperation.Protocol.cs deleted file mode 100644 index 89f48754..00000000 --- a/src/Custom/VectorStores/VectorStoreFileBatchOperation.Protocol.cs +++ /dev/null @@ -1,269 +0,0 @@ -using System; -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Collections.Generic; -using System.ComponentModel; -using System.Threading.Tasks; - -#nullable enable - -namespace OpenAI.VectorStores; - -/// -/// Long-running operation for creating a vector store file batch. -/// -public partial class VectorStoreFileBatchOperation : OperationResult -{ - private readonly ClientPipeline _pipeline; - private readonly Uri _endpoint; - - private readonly string _vectorStoreId; - private readonly string _batchId; - - private PollingInterval? _pollingInterval; - - /// - public override ContinuationToken? RehydrationToken { get; protected set; } - - /// - public override bool IsCompleted { get; protected set; } - - // Generated protocol methods - - /// - /// [Protocol Method] Retrieves a vector store file batch. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch being retrieved. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task GetBatchFileJobAsync(string vectorStoreId, string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(vectorStoreId, batchId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Retrieves a vector store file batch. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch being retrieved. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult GetBatchFileJob(string vectorStoreId, string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateGetVectorStoreFileBatchRequest(vectorStoreId, batchId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - /// - /// [Protocol Method] Cancel a vector store file batch. This attempts to cancel the processing of files in this batch as soon as possible. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual async Task CancelBatchFileJobAsync(string vectorStoreId, string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateCancelVectorStoreFileBatchRequest(vectorStoreId, batchId, options); - return ClientResult.FromResponse(await _pipeline.ProcessMessageAsync(message, options).ConfigureAwait(false)); - } - - /// - /// [Protocol Method] Cancel a vector store file batch. This attempts to cancel the processing of files in this batch as soon as possible. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch to cancel. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// The response returned from the service. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual ClientResult CancelBatchFileJob(string vectorStoreId, string batchId, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - using PipelineMessage message = CreateCancelVectorStoreFileBatchRequest(vectorStoreId, batchId, options); - return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); - } - - /// - /// [Protocol Method] Returns a paginated collection of vector store files in a batch. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch that the files belong to. - /// - /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the - /// default is 20. - /// - /// - /// Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and`desc` - /// for descending order. Allowed values: "asc" | "desc" - /// - /// - /// A cursor for use in pagination. `after` is an object ID that defines your place in the list. - /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - /// subsequent call can include after=obj_foo in order to fetch the next page of the list. - /// - /// - /// A cursor for use in pagination. `before` is an object ID that defines your place in the list. - /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - /// subsequent call can include before=obj_foo in order to fetch the previous page of the list. - /// - /// Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// A collection of service responses, each holding a page of values. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual IAsyncEnumerable GetFileAssociationsAsync(string vectorStoreId, string batchId, int? limit, string order, string after, string before, string filter, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - VectorStoreFileBatchesPageEnumerator enumerator = new VectorStoreFileBatchesPageEnumerator(_pipeline, _endpoint, vectorStoreId, batchId, limit, order, after, before, filter, options); - return PageCollectionHelpers.CreateAsync(enumerator); - } - - /// - /// [Protocol Method] Returns a paginated collection of vector store files in a batch. - /// - /// The ID of the vector store that the file batch belongs to. - /// The ID of the file batch that the files belong to. - /// - /// A limit on the number of objects to be returned. Limit can range between 1 and 100, and the - /// default is 20. - /// - /// - /// Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and`desc` - /// for descending order. Allowed values: "asc" | "desc" - /// - /// - /// A cursor for use in pagination. `after` is an object ID that defines your place in the list. - /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - /// subsequent call can include after=obj_foo in order to fetch the next page of the list. - /// - /// - /// A cursor for use in pagination. `before` is an object ID that defines your place in the list. - /// For instance, if you make a list request and receive 100 objects, ending with obj_foo, your - /// subsequent call can include before=obj_foo in order to fetch the previous page of the list. - /// - /// Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. - /// The request options, which can override default behaviors of the client pipeline on a per-call basis. - /// or is null. - /// or is an empty string, and was expected to be non-empty. - /// Service returned a non-success status code. - /// A collection of service responses, each holding a page of values. - [EditorBrowsable(EditorBrowsableState.Never)] - public virtual IEnumerable GetFileAssociations(string vectorStoreId, string batchId, int? limit, string order, string after, string before, string filter, RequestOptions options) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchId, nameof(batchId)); - - VectorStoreFileBatchesPageEnumerator enumerator = new VectorStoreFileBatchesPageEnumerator(_pipeline, _endpoint, vectorStoreId, batchId, limit, order, after, before, filter, options); - return PageCollectionHelpers.Create(enumerator); - } - - internal PipelineMessage CreateGetVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/vector_stores/", false); - uri.AppendPath(vectorStoreId, true); - uri.AppendPath("/file_batches/", false); - uri.AppendPath(batchId, true); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateCancelVectorStoreFileBatchRequest(string vectorStoreId, string batchId, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "POST"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/vector_stores/", false); - uri.AppendPath(vectorStoreId, true); - uri.AppendPath("/file_batches/", false); - uri.AppendPath(batchId, true); - uri.AppendPath("/cancel", false); - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - internal PipelineMessage CreateGetFilesInVectorStoreBatchesRequest(string vectorStoreId, string batchId, int? limit, string order, string after, string before, string filter, RequestOptions options) - { - var message = _pipeline.CreateMessage(); - message.ResponseClassifier = PipelineMessageClassifier200; - var request = message.Request; - request.Method = "GET"; - var uri = new ClientUriBuilder(); - uri.Reset(_endpoint); - uri.AppendPath("/vector_stores/", false); - uri.AppendPath(vectorStoreId, true); - uri.AppendPath("/file_batches/", false); - uri.AppendPath(batchId, true); - uri.AppendPath("/files", false); - if (limit != null) - { - uri.AppendQuery("limit", limit.Value, true); - } - if (order != null) - { - uri.AppendQuery("order", order, true); - } - if (after != null) - { - uri.AppendQuery("after", after, true); - } - if (before != null) - { - uri.AppendQuery("before", before, true); - } - if (filter != null) - { - uri.AppendQuery("filter", filter, true); - } - request.Uri = uri.ToUri(); - request.Headers.Set("Accept", "application/json"); - message.Apply(options); - return message; - } - - private static PipelineMessageClassifier? _pipelineMessageClassifier200; - private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); -} \ No newline at end of file diff --git a/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs b/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs deleted file mode 100644 index c90532a7..00000000 --- a/src/Custom/VectorStores/VectorStoreFileBatchOperation.cs +++ /dev/null @@ -1,381 +0,0 @@ -using System; -using System.ClientModel; -using System.ClientModel.Primitives; -using System.Threading; -using System.Threading.Tasks; - -#nullable enable - -namespace OpenAI.VectorStores; - -/// -/// Long-running operation for creating a vector store file batch. -/// -public partial class VectorStoreFileBatchOperation : OperationResult -{ - internal VectorStoreFileBatchOperation( - ClientPipeline pipeline, - Uri endpoint, - ClientResult result) - : base(result.GetRawResponse()) - { - _pipeline = pipeline; - _endpoint = endpoint; - - Value = result; - Status = Value.Status; - - _vectorStoreId = Value.VectorStoreId; - _batchId = Value.BatchId; - - IsCompleted = GetIsCompleted(Value.Status); - RehydrationToken = new VectorStoreFileBatchOperationToken(VectorStoreId, BatchId); - } - - /// - /// The current value of the in progress. - /// - public VectorStoreBatchFileJob? Value { get; private set; } - - /// - /// The current status of the in progress. - /// - public VectorStoreBatchFileJobStatus? Status { get; private set; } - - /// - /// The ID of the vector store corresponding to this batch file operation. - /// - public string VectorStoreId { get => _vectorStoreId; } - - /// - /// The ID of the batch file job represented by this operation. - /// - public string BatchId { get => _batchId; } - - /// - /// Recreates a from a rehydration token. - /// - /// The used to obtain the - /// operation status from the service. - /// The rehydration token corresponding to - /// the operation to rehydrate. - /// A token that can be used to cancel the - /// request. - /// The rehydrated operation. -#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - public static async Task RehydrateAsync(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) -#pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - { - Argument.AssertNotNull(client, nameof(client)); - Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); - - VectorStoreFileBatchOperationToken token = VectorStoreFileBatchOperationToken.FromToken(rehydrationToken); - - ClientResult result = await client.GetBatchFileJobAsync(token.VectorStoreId, token.BatchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - PipelineResponse response = result.GetRawResponse(); - VectorStoreBatchFileJob job = VectorStoreBatchFileJob.FromResponse(response); - - return new VectorStoreFileBatchOperation(client.Pipeline, client.Endpoint, FromValue(job, response)); - } - - /// - /// Recreates a from a rehydration token. - /// - /// The used to obtain the - /// operation status from the service. - /// The rehydration token corresponding to - /// the operation to rehydrate. - /// A token that can be used to cancel the - /// request. - /// The rehydrated operation. -#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - public static VectorStoreFileBatchOperation Rehydrate(VectorStoreClient client, ContinuationToken rehydrationToken, CancellationToken cancellationToken = default) -#pragma warning restore OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. - { - Argument.AssertNotNull(client, nameof(client)); - Argument.AssertNotNull(rehydrationToken, nameof(rehydrationToken)); - - VectorStoreFileBatchOperationToken token = VectorStoreFileBatchOperationToken.FromToken(rehydrationToken); - - ClientResult result = client.GetBatchFileJob(token.VectorStoreId, token.BatchId, cancellationToken.ToRequestOptions()); - PipelineResponse response = result.GetRawResponse(); - VectorStoreBatchFileJob job = VectorStoreBatchFileJob.FromResponse(response); - - return new VectorStoreFileBatchOperation(client.Pipeline, client.Endpoint, FromValue(job, response)); - } - - /// - public override async Task WaitForCompletionAsync(CancellationToken cancellationToken = default) - { - _pollingInterval ??= new(); - - while (!IsCompleted) - { - PipelineResponse response = GetRawResponse(); - - await _pollingInterval.WaitAsync(response, cancellationToken); - - ClientResult result = await GetBatchFileJobAsync(cancellationToken).ConfigureAwait(false); - - ApplyUpdate(result); - } - } - - /// - /// Waits for the operation to complete processing on the service. - /// - /// The time to wait between sending requests - /// for status updates from the service. - /// A token that can be used to cancel this - /// method call. - public async Task WaitForCompletionAsync(TimeSpan pollingInterval, CancellationToken cancellationToken = default) - { - _pollingInterval = new(pollingInterval); - - await WaitForCompletionAsync(cancellationToken).ConfigureAwait(false); - } - - /// - public override void WaitForCompletion(CancellationToken cancellationToken = default) - { - _pollingInterval ??= new(); - - while (!IsCompleted) - { - PipelineResponse response = GetRawResponse(); - - _pollingInterval.Wait(response, cancellationToken); - - ClientResult result = GetBatchFileJob(cancellationToken); - - ApplyUpdate(result); - } - } - - /// - /// Waits for the operation to complete processing on the service. - /// - /// The time to wait between sending requests - /// for status updates from the service. - /// A token that can be used to cancel this - /// method call. - public void WaitForCompletion(TimeSpan pollingInterval, CancellationToken cancellationToken = default) - { - _pollingInterval = new(pollingInterval); - - WaitForCompletion(cancellationToken); - } - - private void ApplyUpdate(ClientResult update) - { - Value = update; - Status = Value.Status; - - IsCompleted = GetIsCompleted(Value.Status); - SetRawResponse(update.GetRawResponse()); - } - - private static bool GetIsCompleted(VectorStoreBatchFileJobStatus status) - { - return status == VectorStoreBatchFileJobStatus.Completed || - status == VectorStoreBatchFileJobStatus.Cancelled || - status == VectorStoreBatchFileJobStatus.Failed; - } - - // Generated convenience methods - - /// - /// Gets an existing vector store batch file ingestion job from a known vector store ID and job ID. - /// - /// A token that can be used to cancel this method call. - /// A instance representing the ingestion operation. - public virtual async Task> GetBatchFileJobAsync(CancellationToken cancellationToken = default) - { - ClientResult result = await GetBatchFileJobAsync(_vectorStoreId, _batchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - PipelineResponse response = result.GetRawResponse(); - VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); - return ClientResult.FromValue(value, response); - } - - /// - /// Gets an existing vector store batch file ingestion job from a known vector store ID and job ID. - /// - /// A token that can be used to cancel this method call. - /// A instance representing the ingestion operation. - public virtual ClientResult GetBatchFileJob(CancellationToken cancellationToken = default) - { - ClientResult result = GetBatchFileJob(_vectorStoreId, _batchId, cancellationToken.ToRequestOptions()); - PipelineResponse response = result.GetRawResponse(); - VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); - return ClientResult.FromValue(value, response); - } - - /// - /// Cancels an in-progress . - /// - /// A token that can be used to cancel this method call. - /// An updated instance. - public virtual async Task> CancelBatchFileJobAsync(CancellationToken cancellationToken = default) - { - ClientResult result = await CancelBatchFileJobAsync(_vectorStoreId, _batchId, cancellationToken.ToRequestOptions()).ConfigureAwait(false); - PipelineResponse response = result.GetRawResponse(); - VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); - return ClientResult.FromValue(value, response); - } - - /// - /// Cancels an in-progress . - /// - /// A token that can be used to cancel this method call. - /// An updated instance. - public virtual ClientResult CancelBatchFileJob(CancellationToken cancellationToken = default) - { - ClientResult result = CancelBatchFileJob(_vectorStoreId, _batchId, cancellationToken.ToRequestOptions()); - PipelineResponse response = result.GetRawResponse(); - VectorStoreBatchFileJob value = VectorStoreBatchFileJob.FromResponse(response); - return ClientResult.FromValue(value, response); - } - - /// - /// Gets a page collection of file associations associated with a vector store batch file job, representing the files - /// that were scheduled for ingestion into the vector store. - /// - /// Options describing the collection to return. - /// A token that can be used to cancel this method call. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual AsyncPageCollection GetFileAssociationsAsync( - VectorStoreFileAssociationCollectionOptions? options = default, - CancellationToken cancellationToken = default) - { - VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, - _vectorStoreId, - _batchId, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - options?.Filter?.ToString(), - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); - } - - /// - /// Rehydrates a page collection of file associations from a page token. - /// - /// Page token corresponding to the first page of the collection to rehydrate. - /// A token that can be used to cancel this method call. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual AsyncPageCollection GetFileAssociationsAsync( - ContinuationToken firstPageToken, - CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); - - VectorStoreFileBatchesPageToken pageToken = VectorStoreFileBatchesPageToken.FromToken(firstPageToken); - - if (_vectorStoreId != pageToken.VectorStoreId) - { - throw new ArgumentException( - "Invalid page token. 'VectorStoreId' value does not match page token value.", - nameof(firstPageToken)); - } - - if (_batchId != pageToken.BatchId) - { - throw new ArgumentException( - "Invalid page token. 'BatchId' value does not match page token value.", - nameof(firstPageToken)); - } - - VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.VectorStoreId, - pageToken.BatchId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - pageToken.Filter, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.CreateAsync(enumerator); - } - - /// - /// Gets a page collection of file associations associated with a vector store batch file job, representing the files - /// that were scheduled for ingestion into the vector store. - /// - /// Options describing the collection to return. - /// A token that can be used to cancel this method call. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual PageCollection GetFileAssociations( - VectorStoreFileAssociationCollectionOptions? options = default, - CancellationToken cancellationToken = default) - { - VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, - _vectorStoreId, - _batchId, - options?.PageSize, - options?.Order?.ToString(), - options?.AfterId, - options?.BeforeId, - options?.Filter?.ToString(), - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); - } - - /// - /// Rehydrates a page collection of file associations from a page token. - /// that were scheduled for ingestion into the vector store. - /// - /// Page token corresponding to the first page of the collection to rehydrate. - /// A token that can be used to cancel this method call. - /// holds pages of values. To obtain a collection of values, call - /// . To obtain the current - /// page of values, call . - /// A collection of pages of . - public virtual PageCollection GetFileAssociations( - ContinuationToken firstPageToken, - CancellationToken cancellationToken = default) - { - Argument.AssertNotNull(firstPageToken, nameof(firstPageToken)); - - VectorStoreFileBatchesPageToken pageToken = VectorStoreFileBatchesPageToken.FromToken(firstPageToken); - - if (_vectorStoreId != pageToken.VectorStoreId) - { - throw new ArgumentException( - "Invalid page token. 'VectorStoreId' value does not match page token value.", - nameof(firstPageToken)); - } - - if (_batchId != pageToken.BatchId) - { - throw new ArgumentException( - "Invalid page token. 'BatchId' value does not match page token value.", - nameof(firstPageToken)); - } - - VectorStoreFileBatchesPageEnumerator enumerator = new(_pipeline, _endpoint, - pageToken.VectorStoreId, - pageToken.BatchId, - pageToken.Limit, - pageToken.Order, - pageToken.After, - pageToken.Before, - pageToken.Filter, - cancellationToken.ToRequestOptions()); - - return PageCollectionHelpers.Create(enumerator); - } -} \ No newline at end of file diff --git a/src/Custom/VectorStores/VectorStoreFileBatchOperationToken.cs b/src/Custom/VectorStores/VectorStoreFileBatchOperationToken.cs deleted file mode 100644 index bcda6b72..00000000 --- a/src/Custom/VectorStores/VectorStoreFileBatchOperationToken.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System; -using System.ClientModel; -using System.Diagnostics; -using System.IO; -using System.Text.Json; - -#nullable enable - -namespace OpenAI.VectorStores; - -internal class VectorStoreFileBatchOperationToken : ContinuationToken -{ - public VectorStoreFileBatchOperationToken(string vectorStoreId, string batchId) - { - VectorStoreId = vectorStoreId; - BatchId = batchId; - } - - public string VectorStoreId { get; } - - public string BatchId { get; } - - public override BinaryData ToBytes() - { - using MemoryStream stream = new(); - using Utf8JsonWriter writer = new(stream); - writer.WriteStartObject(); - - writer.WriteString("vectorStoreId", VectorStoreId); - writer.WriteString("batchId", BatchId); - - writer.WriteEndObject(); - - writer.Flush(); - stream.Position = 0; - - return BinaryData.FromStream(stream); - } - - public static VectorStoreFileBatchOperationToken FromToken(ContinuationToken continuationToken) - { - if (continuationToken is VectorStoreFileBatchOperationToken token) - { - return token; - } - - BinaryData data = continuationToken.ToBytes(); - - if (data.ToMemory().Length == 0) - { - throw new ArgumentException("Failed to create VectorStoreFileBatchOperationToken from provided continuationToken.", nameof(continuationToken)); - } - - Utf8JsonReader reader = new(data); - - string vectorStoreId = null!; - string batchId = null!; - - reader.Read(); - - Debug.Assert(reader.TokenType == JsonTokenType.StartObject); - - while (reader.Read()) - { - if (reader.TokenType == JsonTokenType.EndObject) - { - break; - } - - Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); - - string propertyName = reader.GetString()!; - - switch (propertyName) - { - case "vectorStoreId": - reader.Read(); - Debug.Assert(reader.TokenType == JsonTokenType.String); - vectorStoreId = reader.GetString()!; - break; - - case "batchId": - reader.Read(); - Debug.Assert(reader.TokenType == JsonTokenType.String); - batchId = reader.GetString()!; - break; - - default: - throw new JsonException($"Unrecognized property '{propertyName}'."); - } - } - - if (vectorStoreId is null || batchId is null) - { - throw new ArgumentException("Failed to create VectorStoreFileBatchOperationToken from provided continuationToken.", nameof(continuationToken)); - } - - return new(vectorStoreId, batchId); - } -} -