diff --git a/.dotnet/OpenAI.sln b/.dotnet/OpenAI.sln index 5d1edd8c3..f4848b460 100644 --- a/.dotnet/OpenAI.sln +++ b/.dotnet/OpenAI.sln @@ -1,10 +1,12 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29709.97 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34902.65 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenAI", "src\OpenAI.csproj", "{28FF4005-4467-4E36-92E7-DEA27DEB1519}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenAI", "src\OpenAI.csproj", "{28FF4005-4467-4E36-92E7-DEA27DEB1519}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenAI.Tests", "tests\OpenAI.Tests.csproj", "{1F1CD1D4-9932-4B73-99D8-C252A67D4B46}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenAI.Tests", "tests\OpenAI.Tests.csproj", "{1F1CD1D4-9932-4B73-99D8-C252A67D4B46}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.ClientModel", "..\..\azure-sdk-for-net\sdk\core\System.ClientModel\src\System.ClientModel.csproj", "{174AF64C-C129-454D-BFE7-0D05018EC531}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -12,26 +14,6 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Release|Any CPU.Build.0 = Release|Any CPU - {8E9A77AC-792A-4432-8320-ACFD46730401}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8E9A77AC-792A-4432-8320-ACFD46730401}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8E9A77AC-792A-4432-8320-ACFD46730401}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8E9A77AC-792A-4432-8320-ACFD46730401}.Release|Any CPU.Build.0 = Release|Any CPU - {A4241C1F-A53D-474C-9E4E-075054407E74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A4241C1F-A53D-474C-9E4E-075054407E74}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A4241C1F-A53D-474C-9E4E-075054407E74}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A4241C1F-A53D-474C-9E4E-075054407E74}.Release|Any CPU.Build.0 = Release|Any CPU - {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Release|Any CPU.Build.0 = Release|Any CPU - {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Release|Any CPU.Build.0 = Release|Any CPU {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Debug|Any CPU.Build.0 = Debug|Any CPU {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -40,6 +22,10 @@ Global {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Debug|Any CPU.Build.0 = Debug|Any CPU {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Release|Any CPU.ActiveCfg = Release|Any CPU {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Release|Any CPU.Build.0 = Release|Any CPU + {174AF64C-C129-454D-BFE7-0D05018EC531}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {174AF64C-C129-454D-BFE7-0D05018EC531}.Debug|Any CPU.Build.0 = Debug|Any CPU + {174AF64C-C129-454D-BFE7-0D05018EC531}.Release|Any CPU.ActiveCfg = Release|Any CPU + {174AF64C-C129-454D-BFE7-0D05018EC531}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/.dotnet/src/Custom/Assistants/Assistant.cs b/.dotnet/src/Custom/Assistants/Assistant.cs index 872b43884..774893ef4 100644 --- a/.dotnet/src/Custom/Assistants/Assistant.cs +++ b/.dotnet/src/Custom/Assistants/Assistant.cs @@ -18,4 +18,9 @@ public partial class Assistant /// [CodeGenMember("TopP")] public float? NucleusSamplingFactor { get; } + + public override string ToString() + { + return Id; + } } diff --git a/.dotnet/src/Custom/Assistants/AssistantClient.Convenience.cs b/.dotnet/src/Custom/Assistants/AssistantClient.Convenience.cs index e1021bd2f..db43a81c0 100644 --- a/.dotnet/src/Custom/Assistants/AssistantClient.Convenience.cs +++ b/.dotnet/src/Custom/Assistants/AssistantClient.Convenience.cs @@ -130,13 +130,14 @@ public virtual ClientResult CreateMessage( /// timestamp. /// /// A collection of messages that can be enumerated using await foreach. - public virtual AsyncPageableCollection GetMessagesAsync( + public virtual AsyncPageableResult GetMessagesAsync( AssistantThread thread, + int? pageSize = null, ListOrder? resultOrder = default) { Argument.AssertNotNull(thread, nameof(thread)); - return GetMessagesAsync(thread.Id, resultOrder); + return GetMessagesAsync(thread.Id, pageSize, resultOrder); } /// @@ -148,13 +149,16 @@ public virtual AsyncPageableCollection GetMessagesAsync( /// timestamp. /// /// A collection of messages that can be enumerated using foreach. - public virtual PageableCollection GetMessages( - AssistantThread thread, - ListOrder? resultOrder = default) + public virtual PageableResult GetMessages( + AssistantThread thread, + ListOrder? resultOrder = null, + string itemsAfter = default, + string itemsBefore = default, + int? pageSize = null) { Argument.AssertNotNull(thread, nameof(thread)); - return GetMessages(thread.Id, resultOrder); + return GetMessages(thread.Id, resultOrder, itemsAfter, itemsBefore, pageSize); } /// @@ -236,7 +240,7 @@ public virtual ClientResult CreateRun(AssistantThread thread, Assista /// The thread that the run should evaluate. /// The assistant that should be used when evaluating the thread. /// Additional options for the run. - public virtual AsyncResultCollection CreateRunStreamingAsync( + public virtual AsyncCollectionResult CreateRunStreamingAsync( AssistantThread thread, Assistant assistant, RunCreationOptions options = null) @@ -249,7 +253,7 @@ public virtual AsyncResultCollection CreateRunStreamingAsync( /// The thread that the run should evaluate. /// The assistant that should be used when evaluating the thread. /// Additional options for the run. - public virtual ResultCollection CreateRunStreaming( + public virtual CollectionResult CreateRunStreaming( AssistantThread thread, Assistant assistant, RunCreationOptions options = null) @@ -287,7 +291,7 @@ public virtual ClientResult CreateThreadAndRun( /// The assistant that the new run should use. /// Options for the new thread that will be created. /// Additional options to apply to the run that will begin. - public virtual AsyncResultCollection CreateThreadAndRunStreamingAsync( + public virtual AsyncCollectionResult CreateThreadAndRunStreamingAsync( Assistant assistant, ThreadCreationOptions threadOptions = null, RunCreationOptions runOptions = null) @@ -299,7 +303,7 @@ public virtual AsyncResultCollection CreateThreadAndRunStreamin /// The assistant that the new run should use. /// Options for the new thread that will be created. /// Additional options to apply to the run that will begin. - public virtual ResultCollection CreateThreadAndRunStreaming( + public virtual CollectionResult CreateThreadAndRunStreaming( Assistant assistant, ThreadCreationOptions threadOptions = null, RunCreationOptions runOptions = null) @@ -314,13 +318,16 @@ public virtual ResultCollection CreateThreadAndRunStreaming( /// timestamp. /// /// A collection of runs that can be enumerated using await foreach. - public virtual AsyncPageableCollection GetRunsAsync( + public virtual AsyncPageableResult GetRunsAsync( AssistantThread thread, - ListOrder? resultOrder = default) + ListOrder? resultOrder = null, + string itemsAfter = default, + string itemsBefore = default, + int? pageSize = null) { Argument.AssertNotNull(thread, nameof(thread)); - return GetRunsAsync(thread.Id, resultOrder); + return GetRunsAsync(thread.Id, resultOrder, itemsAfter, itemsBefore, pageSize); } /// @@ -332,13 +339,16 @@ public virtual AsyncPageableCollection GetRunsAsync( /// timestamp. /// /// A collection of runs that can be enumerated using foreach. - public virtual PageableCollection GetRuns( + public virtual PageableResult GetRuns( AssistantThread thread, - ListOrder? resultOrder = default) + ListOrder? resultOrder = null, + string itemsAfter = default, + string itemsBefore = default, + int? pageSize = null) { Argument.AssertNotNull(thread, nameof(thread)); - return GetRuns(thread.Id, resultOrder); + return GetRuns(thread.Id, resultOrder, itemsAfter, itemsBefore, pageSize); } /// @@ -390,7 +400,7 @@ public virtual ClientResult SubmitToolOutputsToRun( /// /// The tool outputs, corresponding to instances from the run. /// - public virtual AsyncResultCollection SubmitToolOutputsToRunStreamingAsync( + public virtual AsyncCollectionResult SubmitToolOutputsToRunStreamingAsync( ThreadRun run, IEnumerable toolOutputs) => SubmitToolOutputsToRunStreamingAsync(run?.ThreadId, run?.Id, toolOutputs); @@ -402,7 +412,7 @@ public virtual AsyncResultCollection SubmitToolOutputsToRunStre /// /// The tool outputs, corresponding to instances from the run. /// - public virtual ResultCollection SubmitToolOutputsToRunStreaming( + public virtual CollectionResult SubmitToolOutputsToRunStreaming( ThreadRun run, IEnumerable toolOutputs) => SubmitToolOutputsToRunStreaming(run?.ThreadId, run?.Id, toolOutputs); @@ -432,13 +442,16 @@ public virtual ClientResult CancelRun(ThreadRun run) /// timestamp. /// /// A collection of run steps that can be enumerated using await foreach. - public virtual PageableCollection GetRunSteps( + public virtual PageableResult GetRunSteps( ThreadRun run, - ListOrder? resultOrder = default) + ListOrder? resultOrder = null, + string itemsAfter = default, + string itemsBefore = default, + int? pageSize = null) { Argument.AssertNotNull(run, nameof(run)); - return GetRunSteps(run.ThreadId, run.Id, resultOrder); + return GetRunSteps(run.ThreadId, run.Id, resultOrder, itemsAfter, itemsBefore, pageSize); } /// @@ -450,12 +463,15 @@ public virtual PageableCollection GetRunSteps( /// timestamp. /// /// A collection of run steps that can be enumerated using foreach. - public virtual AsyncPageableCollection GetRunStepsAsync( + public virtual AsyncPageableResult GetRunStepsAsync( ThreadRun run, - ListOrder? resultOrder = default) + ListOrder? resultOrder = null, + string itemsAfter = default, + string itemsBefore = default, + int? pageSize = null) { Argument.AssertNotNull(run, nameof(run)); - return GetRunStepsAsync(run.ThreadId, run.Id, resultOrder); + return GetRunStepsAsync(run.ThreadId, run.Id, resultOrder, itemsAfter, itemsBefore, pageSize); } } diff --git a/.dotnet/src/Custom/Assistants/AssistantClient.cs b/.dotnet/src/Custom/Assistants/AssistantClient.cs index 15838592e..e957999cf 100644 --- a/.dotnet/src/Custom/Assistants/AssistantClient.cs +++ b/.dotnet/src/Custom/Assistants/AssistantClient.cs @@ -105,10 +105,34 @@ public virtual ClientResult CreateAssistant(string model, AssistantCr /// timestamp. /// /// A collection of assistants that can be enumerated using await foreach. - public virtual AsyncPageableCollection GetAssistantsAsync(ListOrder? resultOrder = null) + public virtual AsyncPageableResult GetAssistantsAsync( + ListOrder? resultOrder = null, + string itemsAfter = default, + string itemsBefore = default, + int? pageSize = null) { - return CreateAsyncPageable((continuationToken, pageSize) - => GetAssistantsAsync(pageSize, resultOrder?.ToString(), continuationToken, null, null)); + async Task> pageFuncAsync(string? pageToken = default, string? prevPageToken = default) + { + PageToken requestPageToken = pageToken is null ? + new(itemsAfter, itemsBefore, true) : + ToPageToken(pageToken); + + ClientResult result = await GetAssistantsAsync( + limit: pageSize, + order: resultOrder.ToString(), + after: requestPageToken.After, + before: requestPageToken.Before, + options: null).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + InternalListAssistantsResponse list = ModelReaderWriter.Read(response.Content)!; + + string nextPageToken = FromPageToken(new PageToken(list.LastId, requestPageToken.Before, list.HasMore)); + prevPageToken ??= FromPageToken(new PageToken(itemsAfter, list.FirstId, itemsAfter != list.FirstId)); + + return PageResult.Create(list.Data, response, nextPageToken, prevPageToken); + } + + return PageableResultHelpers.Create(pageFuncAsync, pageFuncAsync); } /// @@ -119,10 +143,38 @@ public virtual AsyncPageableCollection GetAssistantsAsync(ListOrder? /// timestamp. /// /// A collection of assistants that can be enumerated using foreach. - public virtual PageableCollection GetAssistants(ListOrder? resultOrder = null) + public virtual PageableResult GetAssistants( + ListOrder? resultOrder = null, + string itemsAfter = default, + string itemsBefore = default, + int? pageSize = null) { - return CreatePageable((continuationToken, pageSize) - => GetAssistants(pageSize, resultOrder?.ToString(), continuationToken, null, null)); + PageResult getPage(string? pageToken = default, string? prevPageToken = default) + { + PageToken requestPageToken = pageToken is null ? + new(itemsAfter, itemsBefore, null) : + ToPageToken(pageToken); + + ClientResult result = GetAssistants( + limit: pageSize, + order: resultOrder.ToString(), + after: requestPageToken.After, + before: requestPageToken.Before, + options: null); + + PipelineResponse response = result.GetRawResponse(); + InternalListAssistantsResponse list = ModelReaderWriter.Read(response.Content)!; + + string nextPageToken = FromPageToken(new PageToken(list.LastId, itemsBefore, hasMore: true /*list.HasMore*/)); + prevPageToken ??= pageToken is null ? + // We're requesting the first page, so prev page should be null. + null : + FromPageToken(new PageToken(itemsAfter, list.FirstId, hasMore: true)); + + return PageResult.Create(list.Data, response, nextPageToken, prevPageToken); + } + + return PageableResultHelpers.Create(getPage, getPage); } /// @@ -317,14 +369,35 @@ public virtual ClientResult CreateMessage( /// timestamp. /// /// A collection of messages that can be enumerated using await foreach. - public virtual AsyncPageableCollection GetMessagesAsync( + public virtual AsyncPageableResult GetMessagesAsync( string threadId, - ListOrder? resultOrder = null) + int? pageSize = null, + ListOrder? resultOrder = null, + string itemsAfter = null, + string itemsBefore = null) { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - return CreateAsyncPageable((continuationToken, pageSize) - => GetMessagesAsync(threadId, pageSize, resultOrder?.ToString(), continuationToken, null, null)); + async Task> pageFuncAsync(string? pageToken = default, string? prevPageToken = default) + { + PageToken requestPageToken = pageToken is null ? + new(itemsAfter, itemsBefore, true) : + ToPageToken(pageToken); + + ClientResult result = await GetMessagesAsync(threadId, + limit: pageSize, + order: resultOrder.ToString(), + after: requestPageToken.After, + before: requestPageToken.Before, + options: null).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + InternalListMessagesResponse list = ModelReaderWriter.Read(response.Content)!; + + string nextPageToken = FromPageToken(new PageToken(list.LastId, requestPageToken.Before, list.HasMore)); + return PageResult.Create(list.Data, response, nextPageToken, prevPageToken); + } + + return PageableResultHelpers.Create(pageFuncAsync, pageFuncAsync); } /// @@ -336,14 +409,36 @@ public virtual AsyncPageableCollection GetMessagesAsync( /// timestamp. /// /// A collection of messages that can be enumerated using foreach. - public virtual PageableCollection GetMessages( + public virtual PageableResult GetMessages( string threadId, - ListOrder? resultOrder = null) + ListOrder? resultOrder = null, + string itemsAfter = default, + string itemsBefore = default, + int? pageSize = null) { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - return CreatePageable((continuationToken, pageSize) - => GetMessages(threadId, pageSize, resultOrder?.ToString(), continuationToken, null, null)); + PageResult getPage(string? pageToken = default, string? prevPageToken = default) + { + PageToken requestPageToken = pageToken is null ? + new(itemsAfter, itemsBefore, true) : + ToPageToken(pageToken); + + ClientResult result = GetMessages(threadId, + limit: pageSize, + order: resultOrder.ToString(), + after: requestPageToken.After, + before: requestPageToken.Before, + options: null); + PipelineResponse response = result.GetRawResponse(); + InternalListMessagesResponse list = ModelReaderWriter.Read(response.Content)!; + + + string nextPageToken = FromPageToken(new PageToken(list.LastId, requestPageToken.Before, list.HasMore)); + return PageResult.Create(list.Data, response, nextPageToken, prevPageToken); + } + + return PageableResultHelpers.Create(getPage, getPage); } /// @@ -491,7 +586,7 @@ public virtual ClientResult CreateRun(string threadId, string assista /// The ID of the thread that the run should evaluate. /// The ID of the assistant that should be used when evaluating the thread. /// Additional options for the run. - public virtual AsyncResultCollection CreateRunStreamingAsync( + public virtual AsyncCollectionResult CreateRunStreamingAsync( string threadId, string assistantId, RunCreationOptions options = null) @@ -517,7 +612,7 @@ await CreateRunAsync(threadId, options.ToBinaryContent(), StreamRequestOptions) /// The ID of the thread that the run should evaluate. /// The ID of the assistant that should be used when evaluating the thread. /// Additional options for the run. - public virtual ResultCollection CreateRunStreaming( + public virtual CollectionResult CreateRunStreaming( string threadId, string assistantId, RunCreationOptions options = null) @@ -578,7 +673,7 @@ public virtual ClientResult CreateThreadAndRun( /// The ID of the assistant that the new run should use. /// Options for the new thread that will be created. /// Additional options to apply to the run that will begin. - public virtual AsyncResultCollection CreateThreadAndRunStreamingAsync( + public virtual AsyncCollectionResult CreateThreadAndRunStreamingAsync( string assistantId, ThreadCreationOptions threadOptions = null, RunCreationOptions runOptions = null) @@ -589,7 +684,7 @@ public virtual AsyncResultCollection CreateThreadAndRunStreamin runOptions.Stream = true; BinaryContent protocolContent = CreateThreadAndRunProtocolContent(assistantId, threadOptions, runOptions); - async Task getResultAsync() => + async Task getResultAsync() => await CreateThreadAndRunAsync(protocolContent, StreamRequestOptions) .ConfigureAwait(false); @@ -602,7 +697,7 @@ await CreateThreadAndRunAsync(protocolContent, StreamRequestOptions) /// The ID of the assistant that the new run should use. /// Options for the new thread that will be created. /// Additional options to apply to the run that will begin. - public virtual ResultCollection CreateThreadAndRunStreaming( + public virtual CollectionResult CreateThreadAndRunStreaming( string assistantId, ThreadCreationOptions threadOptions = null, RunCreationOptions runOptions = null) @@ -627,14 +722,36 @@ public virtual ResultCollection CreateThreadAndRunStreaming( /// timestamp. /// /// A collection of runs that can be enumerated using await foreach. - public virtual AsyncPageableCollection GetRunsAsync( + public virtual AsyncPageableResult GetRunsAsync( string threadId, - ListOrder? resultOrder = default) + ListOrder? resultOrder = null, + string itemsAfter = default, + string itemsBefore = default, + int? pageSize = null) { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - return CreateAsyncPageable((continuationToken, pageSize) - => GetRunsAsync(threadId, pageSize, resultOrder?.ToString(), continuationToken, null, null)); + async Task> pageFuncAsync(string? pageToken = default, string? prevPageToken = default) + { + PageToken requestPageToken = pageToken is null ? + new(itemsAfter, itemsBefore, true) : + ToPageToken(pageToken); + + ClientResult result = await GetRunsAsync( + threadId, + limit: pageSize, + order: resultOrder.ToString(), + after: requestPageToken.After, + before: requestPageToken.Before, + options: null).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + InternalListRunsResponse list = ModelReaderWriter.Read(response.Content)!; + + string nextPageToken = FromPageToken(new PageToken(list.LastId, requestPageToken.Before, list.HasMore)); + return PageResult.Create(list.Data, response, nextPageToken, prevPageToken); + } + + return PageableResultHelpers.Create(pageFuncAsync, pageFuncAsync); } /// @@ -646,14 +763,36 @@ public virtual AsyncPageableCollection GetRunsAsync( /// timestamp. /// /// A collection of runs that can be enumerated using foreach. - public virtual PageableCollection GetRuns( + public virtual PageableResult GetRuns( string threadId, - ListOrder? resultOrder = default) + ListOrder? resultOrder = null, + string itemsAfter = default, + string itemsBefore = default, + int? pageSize = null) { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - return CreatePageable((continuationToken, pageSize) - => GetRuns(threadId, pageSize, resultOrder?.ToString(), continuationToken, null, null)); + PageResult pageFunc(string? pageToken = default, string? prevPageToken = default) + { + PageToken requestPageToken = pageToken is null ? + new(itemsAfter, itemsBefore, true) : + ToPageToken(pageToken); + + ClientResult result = GetRuns(threadId, + limit: pageSize, + order: resultOrder.ToString(), + + after: requestPageToken.After, + before: requestPageToken.Before, + options: null); + PipelineResponse response = result.GetRawResponse(); + InternalListRunsResponse list = ModelReaderWriter.Read(response.Content)!; + + string nextPageToken = FromPageToken(new PageToken(list.LastId, requestPageToken.Before, list.HasMore)); + return PageResult.Create(list.Data, response, nextPageToken, prevPageToken); + } + + return PageableResultHelpers.Create(pageFunc, pageFunc); } /// @@ -739,7 +878,7 @@ public virtual ClientResult SubmitToolOutputsToRun( /// /// The tool outputs, corresponding to instances from the run. /// - public virtual AsyncResultCollection SubmitToolOutputsToRunStreamingAsync( + public virtual AsyncCollectionResult SubmitToolOutputsToRunStreamingAsync( string threadId, string runId, IEnumerable toolOutputs) @@ -765,7 +904,7 @@ await SubmitToolOutputsToRunAsync(threadId, runId, content, StreamRequestOptions /// /// The tool outputs, corresponding to instances from the run. /// - public virtual ResultCollection SubmitToolOutputsToRunStreaming( + public virtual CollectionResult SubmitToolOutputsToRunStreaming( string threadId, string runId, IEnumerable toolOutputs) @@ -821,16 +960,37 @@ public virtual ClientResult CancelRun(string threadId, string runId) /// timestamp. /// /// A collection of run steps that can be enumerated using await foreach. - public virtual AsyncPageableCollection GetRunStepsAsync( + public virtual AsyncPageableResult GetRunStepsAsync( string threadId, string runId, - ListOrder? resultOrder = default) + ListOrder? resultOrder = null, + string itemsAfter = default, + string itemsBefore = default, + int? pageSize = null) { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - return CreateAsyncPageable((continuationToken, pageSize) - => GetRunStepsAsync(threadId, runId, pageSize, resultOrder?.ToString(), continuationToken, null, null)); + async Task> pageFuncAsync(string? pageToken = default, string? prevPageToken = default) + { + PageToken requestPageToken = pageToken is null ? + new(itemsAfter, itemsBefore, true) : + ToPageToken(pageToken); + + ClientResult result = await GetRunStepsAsync(threadId, runId, + limit: pageSize, + order: resultOrder.ToString(), + after: requestPageToken.After, + before: requestPageToken.Before, + options: null).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + InternalListRunStepsResponse list = ModelReaderWriter.Read(response.Content)!; + + string nextPageToken = FromPageToken(new PageToken(list.LastId, requestPageToken.Before, list.HasMore)); + return PageResult.Create(list.Data, response, nextPageToken, prevPageToken); + } + + return PageableResultHelpers.Create(pageFuncAsync, pageFuncAsync); } /// @@ -843,16 +1003,38 @@ public virtual AsyncPageableCollection GetRunStepsAsync( /// timestamp. /// /// A collection of run steps that can be enumerated using foreach. - public virtual PageableCollection GetRunSteps( + public virtual PageableResult GetRunSteps( string threadId, string runId, - ListOrder? resultOrder = default) + ListOrder? resultOrder = null, + string itemsAfter = default, + string itemsBefore = default, + int? pageSize = null) { Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - return CreatePageable((continuationToken, pageSize) - => GetRunSteps(threadId, runId, pageSize, resultOrder?.ToString(), continuationToken, null, null)); + PageResult pageFunc(string? pageToken = default, string? prevPageToken = default) + { + PageToken requestPageToken = pageToken is null ? + new(itemsAfter, itemsBefore, true) : + ToPageToken(pageToken); + + ClientResult result = GetRunSteps(threadId, runId, + limit: pageSize, + order: resultOrder.ToString(), + after: requestPageToken.After, + before: requestPageToken.Before, + options: null); + PipelineResponse response = result.GetRawResponse(); + InternalListRunStepsResponse list = ModelReaderWriter.Read(response.Content)!; + + string nextPageToken = FromPageToken(new PageToken(list.LastId, requestPageToken.Before, list.HasMore)); + prevPageToken ??= FromPageToken(new PageToken(itemsAfter, list.FirstId, itemsAfter != list.FirstId)); + return PageResult.Create(list.Data, response, nextPageToken, prevPageToken); + } + + return PageableResultHelpers.Create(pageFunc, pageFunc); } /// @@ -864,7 +1046,7 @@ public virtual PageableCollection GetRunSteps( /// A instance corresponding to the specified step. public virtual async Task> GetRunStepAsync(string threadId, string runId, string stepId) { - ClientResult protocolResult = await GetRunStepAsync(threadId, runId, stepId, null).ConfigureAwait(false); + ClientResult protocolResult = await GetRunStepAsync(runId, stepId, null).ConfigureAwait(false); return CreateResultFromProtocol(protocolResult, RunStep.FromResponse); } @@ -877,7 +1059,7 @@ public virtual async Task> GetRunStepAsync(string threadId /// A instance corresponding to the specified step. public virtual ClientResult GetRunStep(string threadId, string runId, string stepId) { - ClientResult protocolResult = GetRunStep(threadId, runId, stepId, null); + ClientResult protocolResult = GetRunStep(runId, stepId, null); return CreateResultFromProtocol(protocolResult, RunStep.FromResponse); } diff --git a/.dotnet/src/Custom/Assistants/Streaming/AsyncStreamingUpdateCollection.cs b/.dotnet/src/Custom/Assistants/Streaming/AsyncStreamingUpdateCollection.cs index b3f87cf07..60a7a7513 100644 --- a/.dotnet/src/Custom/Assistants/Streaming/AsyncStreamingUpdateCollection.cs +++ b/.dotnet/src/Custom/Assistants/Streaming/AsyncStreamingUpdateCollection.cs @@ -13,7 +13,7 @@ namespace OpenAI.Assistants; /// /// Implementation of collection abstraction over streaming assistant updates. /// -internal class AsyncStreamingUpdateCollection : AsyncResultCollection +internal class AsyncStreamingUpdateCollection : AsyncCollectionResult { private readonly Func> _getResultAsync; diff --git a/.dotnet/src/Custom/Assistants/Streaming/StreamingUpdateCollection.cs b/.dotnet/src/Custom/Assistants/Streaming/StreamingUpdateCollection.cs index 4f6e6c943..05677f552 100644 --- a/.dotnet/src/Custom/Assistants/Streaming/StreamingUpdateCollection.cs +++ b/.dotnet/src/Custom/Assistants/Streaming/StreamingUpdateCollection.cs @@ -12,7 +12,7 @@ namespace OpenAI.Assistants; /// /// Implementation of collection abstraction over streaming assistant updates. /// -internal class StreamingUpdateCollection : ResultCollection +internal class StreamingUpdateCollection : CollectionResult { private readonly Func _getResult; diff --git a/.dotnet/src/Custom/Chat/ChatClient.cs b/.dotnet/src/Custom/Chat/ChatClient.cs index abc04ab5d..d1e40bb26 100644 --- a/.dotnet/src/Custom/Chat/ChatClient.cs +++ b/.dotnet/src/Custom/Chat/ChatClient.cs @@ -111,7 +111,7 @@ public virtual ClientResult CompleteChat(IEnumerable The messages to provide as input for chat completion. /// Additional options for the chat completion request. /// A streaming result with incremental chat completion updates. - public virtual AsyncResultCollection CompleteChatStreamingAsync(IEnumerable messages, ChatCompletionOptions options = null) + public virtual AsyncCollectionResult CompleteChatStreamingAsync(IEnumerable messages, ChatCompletionOptions options = null) { Argument.AssertNotNull(messages, nameof(messages)); @@ -136,7 +136,7 @@ async Task getResultAsync() => /// The messages to provide as input for chat completion. /// Additional options for the chat completion request. /// A streaming result with incremental chat completion updates. - public virtual ResultCollection CompleteChatStreaming(IEnumerable messages, ChatCompletionOptions options = null) + public virtual CollectionResult CompleteChatStreaming(IEnumerable messages, ChatCompletionOptions options = null) { Argument.AssertNotNull(messages, nameof(messages)); diff --git a/.dotnet/src/Custom/Chat/Internal/AsyncStreamingChatCompletionUpdateCollection.cs b/.dotnet/src/Custom/Chat/Internal/AsyncStreamingChatCompletionUpdateCollection.cs index 320cedbf1..a7aacfc84 100644 --- a/.dotnet/src/Custom/Chat/Internal/AsyncStreamingChatCompletionUpdateCollection.cs +++ b/.dotnet/src/Custom/Chat/Internal/AsyncStreamingChatCompletionUpdateCollection.cs @@ -14,7 +14,7 @@ namespace OpenAI.Chat; /// /// Implementation of collection abstraction over streaming chat updates. /// -internal class AsyncStreamingChatCompletionUpdateCollection : AsyncResultCollection +internal class AsyncStreamingChatCompletionUpdateCollection : AsyncCollectionResult { private readonly Func> _getResultAsync; diff --git a/.dotnet/src/Custom/Chat/Internal/StreamingChatCompletionUpdateCollection.cs b/.dotnet/src/Custom/Chat/Internal/StreamingChatCompletionUpdateCollection.cs index fe4546992..af2918cfe 100644 --- a/.dotnet/src/Custom/Chat/Internal/StreamingChatCompletionUpdateCollection.cs +++ b/.dotnet/src/Custom/Chat/Internal/StreamingChatCompletionUpdateCollection.cs @@ -13,7 +13,7 @@ namespace OpenAI.Chat; /// /// Implementation of collection abstraction over streaming chat updates. /// -internal class StreamingChatCompletionUpdateCollection : ResultCollection +internal class StreamingChatCompletionUpdateCollection : CollectionResult { private readonly Func _getResult; diff --git a/.dotnet/src/Custom/Common/InternalListHelpers.cs b/.dotnet/src/Custom/Common/InternalListHelpers.cs index 4537ad780..db997747c 100644 --- a/.dotnet/src/Custom/Common/InternalListHelpers.cs +++ b/.dotnet/src/Custom/Common/InternalListHelpers.cs @@ -1,37 +1,85 @@ +using System; using System.ClientModel; using System.ClientModel.Primitives; +using System.Diagnostics; using System.Runtime.CompilerServices; using System.Threading.Tasks; +#nullable enable + namespace OpenAI; internal static class InternalListHelpers { - internal delegate Task AsyncListResponseFunc(string continuationToken, int? pageSize); - internal delegate ClientResult ListResponseFunc(string continuationToken, int? pageSize); + internal delegate Task AsyncListResponseFunc(string? pageToken); + internal delegate ClientResult ListResponseFunc(string? pageToken); - internal static AsyncPageableCollection CreateAsyncPageable(AsyncListResponseFunc listResponseFunc) - where U : IJsonModel, IInternalListResponse - { - async Task> pageFunc(string continuationToken, int? pageSize) - => GetPageFromProtocol(await listResponseFunc(continuationToken, pageSize).ConfigureAwait(false)); - return PageableResultHelpers.Create((pageSize) => pageFunc(null, pageSize), pageFunc); - } + //internal static AsyncPageableResult CreateAsyncPageable(AsyncListResponseFunc listResponseFunc) + // where U : IJsonModel, IInternalListResponse + //{ + // async Task> pageFunc(string? pageToken) + // => GetPageFromProtocol(pageToken, await listResponseFunc(pageToken).ConfigureAwait(false)); + // return PageableResultHelpers.Create(pageFunc, pageFunc); + //} + + //internal static AsyncPageableResult CreateAsyncPageable( + //AsyncListResponseFunc firstListResponseFunc, + //AsyncListResponseFunc nextListResponseFunc) + //where U : IJsonModel, IInternalListResponse + //{ + // async Task> firstPageFunc(string? pageToken) + // => GetPageFromProtocol(pageToken, await firstListResponseFunc(pageToken).ConfigureAwait(false)); + // async Task> nextPageFunc(string? pageToken) + // => GetPageFromProtocol(pageToken, await nextListResponseFunc(pageToken).ConfigureAwait(false)); + // return PageableResultHelpers.Create(firstPageFunc, nextPageFunc); + //} + + //internal static PageableResult CreatePageable(ListResponseFunc listResponseFunc) + // where U : IJsonModel, IInternalListResponse + //{ + // PageResult pageFunc(string? pageToken) + // => GetPageFromProtocol(pageToken, listResponseFunc(pageToken)); + // return PageableResultHelpers.Create(pageFunc, pageFunc); + //} + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //private static PageResult GetPageFromProtocol( + // string? pageToken, ClientResult protocolResult) + // where UInternalList : IJsonModel, IInternalListResponse + //{ + // PageToken token = ToPageToken(pageToken); - internal static PageableCollection CreatePageable(ListResponseFunc listResponseFunc) - where U : IJsonModel, IInternalListResponse + // PipelineResponse response = protocolResult.GetRawResponse(); + // IInternalListResponse values = ModelReaderWriter.Read(response.Content)!; + + // PageToken nextPageToken = new(token.Order, values.LastId, token.Before, values.HasMore); + // PageToken prevPageToken = new(token.Order, token.After, values.FirstId, values.HasMore); + + // return PageResult.Create(values.Data, response, + // FromPageToken(nextPageToken), + // FromPageToken(prevPageToken)); + //} + + internal static PageToken ToPageToken(string? pageToken) { - ResultPage pageFunc(string continuationToken, int? pageSize) - => GetPageFromProtocol(listResponseFunc(continuationToken, pageSize)); - return PageableResultHelpers.Create((pageSize) => pageFunc(null, pageSize), pageFunc); + if (pageToken is null) + { + return new PageToken(null, null, true); + } + + PageToken? token = ModelReaderWriter.Read(BinaryData.FromString(pageToken)); + Debug.Assert(token is not null); + return token!; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ResultPage GetPageFromProtocol(ClientResult protocolResult) - where UInternalList : IJsonModel, IInternalListResponse + internal static string? FromPageToken(PageToken pageToken) { - PipelineResponse response = protocolResult.GetRawResponse(); - IInternalListResponse values = ModelReaderWriter.Read(response.Content); - return ResultPage.Create(values.Data, values.HasMore ? values.LastId : null, response); + if (!(pageToken.HasMore == true)) + { + return null; + } + + BinaryData data = pageToken.Write(ModelReaderWriterOptions.Json); + return data.ToString(); } } diff --git a/.dotnet/src/Custom/Common/PageToken.cs b/.dotnet/src/Custom/Common/PageToken.cs new file mode 100644 index 000000000..8cf617d8a --- /dev/null +++ b/.dotnet/src/Custom/Common/PageToken.cs @@ -0,0 +1,121 @@ +using System; +using System.ClientModel.Primitives; +using System.Diagnostics; +using System.Text.Json; + +#nullable enable + +namespace OpenAI; + +internal class PageToken : IJsonModel +{ + public PageToken() { } + + public PageToken(string? after, string? before, bool? hasMore) + { + After = after; + Before = before; + HasMore = hasMore; + } + + public string? After { get; } + public string? Before { get; } + public bool? HasMore { get; } + + public PageToken Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + => DeserializePageToken(ref reader); + + public PageToken Create(BinaryData data, ModelReaderWriterOptions options) + { + Utf8JsonReader reader = new(data); + return DeserializePageToken(ref reader); + } + + internal static PageToken DeserializePageToken(ref Utf8JsonReader reader) + { + string? after = null; + string? before = null; + bool? hasMore = null; + + // Read start object + reader.Read(); + + Debug.Assert(reader.TokenType == JsonTokenType.StartObject); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + break; + } + + Debug.Assert(reader.TokenType == JsonTokenType.PropertyName); + + string name = reader.GetString()!; + + switch (name) + { + case "after": + reader.Read(); + + Debug.Assert(reader.TokenType == JsonTokenType.String); + + after = reader.GetString()!; + break; + case "before": + reader.Read(); + + Debug.Assert(reader.TokenType == JsonTokenType.String); + + before = reader.GetString()!; + break; + + case "has_more": + reader.Read(); + + Debug.Assert( + reader.TokenType == JsonTokenType.True || + reader.TokenType == JsonTokenType.False); + + hasMore = reader.GetBoolean(); + break; + + default: + break; + } + } + + return new PageToken(after, before, hasMore); + } + + public string GetFormatFromOptions(ModelReaderWriterOptions options) + => "J"; + + public void Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + writer.WriteStartObject(); + + if (After is not null) + { + writer.WritePropertyName("after"); + writer.WriteStringValue(After); + } + + if (Before is not null) + { + writer.WritePropertyName("before"); + writer.WriteStringValue(Before); + } + + if (HasMore is not null) + { + writer.WritePropertyName("has_more"); + writer.WriteBooleanValue(HasMore.Value); + } + + writer.WriteEndObject(); + } + + public BinaryData Write(ModelReaderWriterOptions options) + => ModelReaderWriter.Write(this, ModelReaderWriterOptions.Json); +} diff --git a/.dotnet/src/Custom/Common/PageableResultHelpers.cs b/.dotnet/src/Custom/Common/PageableResultHelpers.cs index 23290c932..b191b056f 100644 --- a/.dotnet/src/Custom/Common/PageableResultHelpers.cs +++ b/.dotnet/src/Custom/Common/PageableResultHelpers.cs @@ -1,5 +1,6 @@ using System; using System.ClientModel; +using System.ClientModel.Primitives; using System.Collections.Generic; using System.Threading.Tasks; @@ -9,85 +10,81 @@ namespace OpenAI; internal class PageableResultHelpers { - public static PageableCollection Create(Func> firstPageFunc, Func>? nextPageFunc, int? pageSize = default) where T : notnull - { - ResultPage first(string? _, int? pageSizeHint) => firstPageFunc(pageSizeHint); - return new FuncPageable(first, nextPageFunc, pageSize); - } + public static PageableResult Create(Func> getInitialPage, Func>? getNextPage) where T : notnull + => new FuncPageable(getInitialPage, getNextPage); - public static AsyncPageableCollection Create(Func>> firstPageFunc, Func>>? nextPageFunc, int? pageSize = default) where T : notnull - { - Task> first(string? _, int? pageSizeHint) => firstPageFunc(pageSizeHint); - return new FuncAsyncPageable(first, nextPageFunc, pageSize); - } + public static AsyncPageableResult Create(Func>> getInitialPage, Func>>? getNextPage) where T : notnull + => new FuncAsyncPageable(getInitialPage, getNextPage); - private class FuncAsyncPageable : AsyncPageableCollection where T : notnull + private class FuncAsyncPageable : AsyncPageableResult where T : notnull { - private readonly Func>> _firstPageFunc; - private readonly Func>>? _nextPageFunc; - private readonly int? _defaultPageSize; + private readonly Func>> _getInitialPage; + private readonly Func>>? _getNextPage; - public FuncAsyncPageable(Func>> firstPageFunc, Func>>? nextPageFunc, int? defaultPageSize = default) + public FuncAsyncPageable(Func>> getInitialPage, Func>>? getNextPage) { - _firstPageFunc = firstPageFunc; - _nextPageFunc = nextPageFunc; - _defaultPageSize = defaultPageSize; + _getInitialPage = getInitialPage; + _getNextPage = getNextPage; } - public override async IAsyncEnumerable> AsPages(string? continuationToken = default, int? pageSizeHint = default) + public override async IAsyncEnumerable> AsPages(string? pageToken = default) { - Func>>? pageFunc = string.IsNullOrEmpty(continuationToken) ? _firstPageFunc : _nextPageFunc; + Func>>? getPage = _getInitialPage; - if (pageFunc == null) + if (getPage == null) { yield break; } - int? pageSize = pageSizeHint ?? _defaultPageSize; + string? requestPageToken = pageToken; + string? prevPageToken = null; + do { - ResultPage page = await pageFunc(continuationToken, pageSize).ConfigureAwait(false); + PageResult page = await getPage(requestPageToken, prevPageToken).ConfigureAwait(false); SetRawResponse(page.GetRawResponse()); yield return page; - continuationToken = page.ContinuationToken; - pageFunc = _nextPageFunc; + prevPageToken = requestPageToken; + requestPageToken = page.NextPageToken; + getPage = _getNextPage; } - while (!string.IsNullOrEmpty(continuationToken) && pageFunc != null); + while (!string.IsNullOrEmpty(pageToken) && getPage != null); } } - private class FuncPageable : PageableCollection where T : notnull + private class FuncPageable : PageableResult where T : notnull { - private readonly Func> _firstPageFunc; - private readonly Func>? _nextPageFunc; - private readonly int? _defaultPageSize; + private readonly Func> _getInitialPage; + private readonly Func>? _getNextPage; - public FuncPageable(Func> firstPageFunc, Func>? nextPageFunc, int? defaultPageSize = default) + public FuncPageable(Func> getInitialPage, Func>? getNextPage) { - _firstPageFunc = firstPageFunc; - _nextPageFunc = nextPageFunc; - _defaultPageSize = defaultPageSize; + _getInitialPage = getInitialPage; + _getNextPage = getNextPage; } - public override IEnumerable> AsPages(string? continuationToken = default, int? pageSizeHint = default) + public override IEnumerable> AsPages(string? pageToken = default) { - Func>? pageFunc = string.IsNullOrEmpty(continuationToken) ? _firstPageFunc : _nextPageFunc; + Func>? getPage = _getInitialPage; - if (pageFunc == null) + if (getPage == null) { yield break; } - int? pageSize = pageSizeHint ?? _defaultPageSize; + string? requestPageToken = pageToken; + string? prevPageToken = null; + do { - ResultPage page = pageFunc(continuationToken, pageSize); + PageResult page = getPage(requestPageToken, prevPageToken); SetRawResponse(page.GetRawResponse()); yield return page; - continuationToken = page.ContinuationToken; - pageFunc = _nextPageFunc; + prevPageToken = requestPageToken; + requestPageToken = page.NextPageToken; + getPage = _getNextPage; } - while (!string.IsNullOrEmpty(continuationToken) && pageFunc != null); + while (!string.IsNullOrEmpty(requestPageToken) && getPage != null); } } } diff --git a/.dotnet/src/Custom/VectorStores/VectorStoreClient.Convenience.cs b/.dotnet/src/Custom/VectorStores/VectorStoreClient.Convenience.cs index 3917b5171..2beb8e983 100644 --- a/.dotnet/src/Custom/VectorStores/VectorStoreClient.Convenience.cs +++ b/.dotnet/src/Custom/VectorStores/VectorStoreClient.Convenience.cs @@ -98,11 +98,12 @@ public virtual ClientResult AddFileToVectorStore(Vec /// A collection of instances that can be asynchronously enumerated via /// await foreach. /// - public virtual AsyncPageableCollection GetFileAssociationsAsync( + public virtual AsyncPageableResult GetFileAssociationsAsync( VectorStore vectorStore, + int? pageSize = null, ListOrder? resultOrder = null, VectorStoreFileStatusFilter? filter = null) - => GetFileAssociationsAsync(vectorStore?.Id, resultOrder, filter); + => GetFileAssociationsAsync(vectorStore?.Id, pageSize, resultOrder, filter); /// /// Gets the collection of instances representing file inclusions in the @@ -122,11 +123,12 @@ public virtual AsyncPageableCollection GetFileAssoci /// A collection of instances that can be synchronously enumerated via /// foreach. /// - public virtual PageableCollection GetFileAssociations( + public virtual PageableResult GetFileAssociations( VectorStore vectorStore, + int? pageSize = null, ListOrder? resultOrder = null, VectorStoreFileStatusFilter? filter = null) - => GetFileAssociations(vectorStore?.Id, resultOrder); + => GetFileAssociations(vectorStore?.Id, pageSize, resultOrder); /// /// Gets a instance representing an existing association between a known @@ -243,11 +245,12 @@ public virtual ClientResult CancelBatchFileJob(VectorSt /// A collection of instances that can be asynchronously enumerated via /// await foreach. /// - public virtual AsyncPageableCollection GetFileAssociationsAsync( + public virtual AsyncPageableResult GetFileAssociationsAsync( VectorStoreBatchFileJob batchJob, + int? pageSize = null, ListOrder? resultOrder = null, VectorStoreFileStatusFilter? filter = null) - => GetFileAssociationsAsync(batchJob?.VectorStoreId, batchJob?.BatchId, resultOrder, filter); + => GetFileAssociationsAsync(batchJob?.VectorStoreId, batchJob?.BatchId, pageSize, resultOrder, filter); /// /// Gets the collection of file associations associated with a vector store batch file job, representing the files @@ -265,10 +268,11 @@ public virtual AsyncPageableCollection GetFileAssoci /// A collection of instances that can be synchronously enumerated via /// foreach. /// - public virtual PageableCollection GetFileAssociations( + public virtual PageableResult GetFileAssociations( VectorStoreBatchFileJob batchJob, + int? pageSize = null, ListOrder? resultOrder = null, VectorStoreFileStatusFilter? filter = null) - => GetFileAssociations(batchJob?.VectorStoreId, batchJob?.BatchId, resultOrder, filter); + => GetFileAssociations(batchJob?.VectorStoreId, batchJob?.BatchId, pageSize, resultOrder, filter); } diff --git a/.dotnet/src/Custom/VectorStores/VectorStoreClient.cs b/.dotnet/src/Custom/VectorStores/VectorStoreClient.cs index 501076115..5a710f79d 100644 --- a/.dotnet/src/Custom/VectorStores/VectorStoreClient.cs +++ b/.dotnet/src/Custom/VectorStores/VectorStoreClient.cs @@ -47,7 +47,7 @@ public VectorStoreClient(ApiKeyCredential credential, OpenAIClientOptions option OpenAIClient.CreatePipeline(OpenAIClient.GetApiKey(credential, requireExplicitCredential: true), options), OpenAIClient.GetEndpoint(options), options) - {} + { } /// /// Initializes a new instance of that will use an API key from the OPENAI_API_KEY @@ -64,7 +64,7 @@ public VectorStoreClient(OpenAIClientOptions options = null) OpenAIClient.CreatePipeline(OpenAIClient.GetApiKey(), options), OpenAIClient.GetEndpoint(options), options) - {} + { } /// Initializes a new instance of VectorStoreClient. /// The HTTP pipeline for sending and receiving REST requests and responses. @@ -138,10 +138,14 @@ public virtual ClientResult DeleteVectorStore(string vectorStoreId) /// A collection of instances that can be asynchronously enumerated via /// await foreach. /// - public virtual AsyncPageableCollection GetVectorStoresAsync(ListOrder? resultOrder = null) + public virtual AsyncPageableResult GetVectorStoresAsync( + int? pageSize = null, + ListOrder? resultOrder = null) { - return CreateAsyncPageable((continuationToken, pageSize) - => GetVectorStoresAsync(pageSize, resultOrder?.ToString(), continuationToken, null, null)); + throw new NotImplementedException(); + //return CreateAsyncPageable( + // pageToken => + // GetVectorStoresAsync(limit: pageSize, resultOrder?.ToString(), pageToken, null, null)); } /// @@ -154,10 +158,12 @@ public virtual AsyncPageableCollection GetVectorStoresAsync(ListOrd /// /// A collection of instances that can be synchronously enumerated via foreach. /// - public virtual PageableCollection GetVectorStores(ListOrder? resultOrder = null) + public virtual PageableResult GetVectorStores(int? pageSize = null, ListOrder? resultOrder = null) { - return CreatePageable((continuationToken, pageSize) - => GetVectorStores(pageSize, resultOrder?.ToString(), continuationToken, null, null)); + throw new NotImplementedException(); + //return CreatePageable( + // pageToken => + // GetVectorStores(limit: pageSize, resultOrder?.ToString(), pageToken, null, null)); } /// @@ -212,15 +218,19 @@ public virtual ClientResult AddFileToVectorStore(str /// A collection of instances that can be asynchronously enumerated via /// await foreach. /// - public virtual AsyncPageableCollection GetFileAssociationsAsync( + public virtual AsyncPageableResult GetFileAssociationsAsync( string vectorStoreId, + int? pageSize = null, ListOrder? resultOrder = null, VectorStoreFileStatusFilter? filter = null) { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - return CreateAsyncPageable( - (continuationToken, pageSize) => GetFileAssociationsAsync( - vectorStoreId, pageSize, resultOrder?.ToString(), continuationToken, null, filter?.ToString(), null)); + throw new NotImplementedException(); + + //Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + + //return CreateAsyncPageable( + // pageToken => + // GetFileAssociationsAsync(vectorStoreId, limit: pageSize, resultOrder?.ToString(), pageToken, null, filter?.ToString(), null)); } /// @@ -241,12 +251,16 @@ public virtual AsyncPageableCollection GetFileAssoci /// A collection of instances that can be synchronously enumerated via /// foreach. /// - public virtual PageableCollection GetFileAssociations(string vectorStoreId, ListOrder? resultOrder = null, VectorStoreFileStatusFilter? filter = null) + public virtual PageableResult GetFileAssociations(string vectorStoreId, + int? pageSize = null, + ListOrder? resultOrder = null, + VectorStoreFileStatusFilter? filter = null) { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - return CreatePageable( - (continuationToken, pageSize) => GetFileAssociations( - vectorStoreId, pageSize, resultOrder?.ToString(), continuationToken, null, filter?.ToString(), null)); + throw new NotImplementedException(); + //Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + //return CreatePageable( + // pageToken => + // GetFileAssociations(vectorStoreId, limit: pageSize, resultOrder?.ToString(), pageToken, null, filter?.ToString(), null)); } /// @@ -458,18 +472,21 @@ public virtual ClientResult CancelBatchFileJob(string v /// A collection of instances that can be asynchronously enumerated via /// await foreach. /// - public virtual AsyncPageableCollection GetFileAssociationsAsync( + public virtual AsyncPageableResult GetFileAssociationsAsync( string vectorStoreId, string batchJobId, + int? pageSize = null, ListOrder? resultOrder = null, VectorStoreFileStatusFilter? filter = null) { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchJobId, nameof(batchJobId)); + throw new NotImplementedException(); + + //Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + //Argument.AssertNotNullOrEmpty(batchJobId, nameof(batchJobId)); - return CreateAsyncPageable( - (continuationToken, pageSize) => GetFileAssociationsAsync - (vectorStoreId, batchJobId, pageSize, resultOrder?.ToString(), continuationToken, null, filter?.ToString(), null)); + //return CreateAsyncPageable( + // pageToken + // => GetFileAssociationsAsync(vectorStoreId, batchJobId, limit: pageSize, resultOrder?.ToString(), pageToken, null, filter?.ToString(), null)); } /// @@ -493,17 +510,20 @@ public virtual AsyncPageableCollection GetFileAssoci /// A collection of instances that can be synchronously enumerated via /// foreach. /// - public virtual PageableCollection GetFileAssociations( + public virtual PageableResult GetFileAssociations( string vectorStoreId, string batchJobId, + int? pageSize = null, ListOrder? resultOrder = null, VectorStoreFileStatusFilter? filter = null) { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - Argument.AssertNotNullOrEmpty(batchJobId, nameof(batchJobId)); + throw new NotImplementedException(); + + //Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + //Argument.AssertNotNullOrEmpty(batchJobId, nameof(batchJobId)); - return CreatePageable( - (continuationToken, pageSize) => GetFileAssociations - (vectorStoreId, batchJobId, pageSize, resultOrder?.ToString(), continuationToken, null, filter?.ToString(), null)); + //return CreatePageable( + // pageToken => + // GetFileAssociations(vectorStoreId, batchJobId, limit: pageSize, resultOrder?.ToString(), pageToken, null, filter?.ToString(), null)); } } diff --git a/.dotnet/src/OpenAI.csproj b/.dotnet/src/OpenAI.csproj index d995dc2d7..81fad2709 100644 --- a/.dotnet/src/OpenAI.csproj +++ b/.dotnet/src/OpenAI.csproj @@ -10,7 +10,9 @@ False - + + + \ No newline at end of file diff --git a/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGeneration.cs b/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGeneration.cs index 0bbd40d85..182164c90 100644 --- a/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGeneration.cs +++ b/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGeneration.cs @@ -108,8 +108,8 @@ public void Sample01_RetrievalAugmentedGeneration() } while (!threadRun.Status.IsTerminal); // Finally, we'll print out the full history for the thread that includes the augmented generation - PageableCollection messages - = assistantClient.GetMessages(threadRun.ThreadId, ListOrder.OldestFirst); + PageableResult messages + = assistantClient.GetMessages(threadRun.ThreadId, resultOrder: ListOrder.OldestFirst); foreach (ThreadMessage message in messages) { diff --git a/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGenerationAsync.cs b/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGenerationAsync.cs index 146b16fb5..8b0f97015 100644 --- a/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGenerationAsync.cs +++ b/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGenerationAsync.cs @@ -109,8 +109,8 @@ public async Task Sample01_RetrievalAugmentedGenerationAsync() } while (!threadRun.Status.IsTerminal); // Finally, we'll print out the full history for the thread that includes the augmented generation - AsyncPageableCollection messages - = assistantClient.GetMessagesAsync(threadRun.ThreadId, ListOrder.OldestFirst); + AsyncPageableResult messages + = assistantClient.GetMessagesAsync(threadRun.ThreadId, resultOrder: ListOrder.OldestFirst); ; await foreach (ThreadMessage message in messages) { diff --git a/.dotnet/tests/Samples/Assistants/Sample02_FunctionCalling.cs b/.dotnet/tests/Samples/Assistants/Sample02_FunctionCalling.cs index 7d71e57bd..082e12b16 100644 --- a/.dotnet/tests/Samples/Assistants/Sample02_FunctionCalling.cs +++ b/.dotnet/tests/Samples/Assistants/Sample02_FunctionCalling.cs @@ -153,7 +153,7 @@ string GetCurrentWeather(string location, string unit = "celsius") // With the run complete, list the messages and display their content if (run.Status == RunStatus.Completed) { - PageableCollection messages + PageableResult messages = client.GetMessages(run.ThreadId, resultOrder: ListOrder.OldestFirst); foreach (ThreadMessage message in messages) diff --git a/.dotnet/tests/Samples/Assistants/Sample02_FunctionCallingAsync.cs b/.dotnet/tests/Samples/Assistants/Sample02_FunctionCallingAsync.cs index 04a8f6b1a..a0d8c524c 100644 --- a/.dotnet/tests/Samples/Assistants/Sample02_FunctionCallingAsync.cs +++ b/.dotnet/tests/Samples/Assistants/Sample02_FunctionCallingAsync.cs @@ -153,7 +153,7 @@ string GetCurrentWeather(string location, string unit = "celsius") // With the run complete, list the messages and display their content if (run.Status == RunStatus.Completed) { - AsyncPageableCollection messages + AsyncPageableResult messages = client.GetMessagesAsync(run.ThreadId, resultOrder: ListOrder.OldestFirst); await foreach (ThreadMessage message in messages) diff --git a/.dotnet/tests/Samples/Assistants/Sample02b_FunctionCallingStreaming.cs b/.dotnet/tests/Samples/Assistants/Sample02b_FunctionCallingStreaming.cs index 49c6f346e..8222d36e8 100644 --- a/.dotnet/tests/Samples/Assistants/Sample02b_FunctionCallingStreaming.cs +++ b/.dotnet/tests/Samples/Assistants/Sample02b_FunctionCallingStreaming.cs @@ -91,7 +91,7 @@ public async Task Sample02b_FunctionCallingStreaming() #region Step 3 - Initiate a streaming run // TODO: replace this with finalized enumerable result pattern - AsyncResultCollection asyncUpdates + AsyncCollectionResult asyncUpdates = client.CreateRunStreamingAsync(thread, assistant); ThreadRun currentRun = null; diff --git a/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPagination.cs b/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPagination.cs index ce57fc8da..3ce0afbba 100644 --- a/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPagination.cs +++ b/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPagination.cs @@ -16,7 +16,7 @@ public void Sample03_ListAssistantsWithPagination() int count = 0; - PageableCollection assistants = client.GetAssistants(); + PageableResult assistants = client.GetAssistants(); foreach (Assistant assistant in assistants) { Console.WriteLine($"[{count,3}] {assistant.Id} {assistant.CreatedAt:s} {assistant.Name}"); diff --git a/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPaginationAsync.cs b/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPaginationAsync.cs index 3b2122ec9..35a018528 100644 --- a/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPaginationAsync.cs +++ b/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPaginationAsync.cs @@ -17,7 +17,7 @@ public async Task Sample03_ListAssistantsWithPaginationAsync() int count = 0; - AsyncPageableCollection assistants = client.GetAssistantsAsync(); + AsyncPageableResult assistants = client.GetAssistantsAsync(); await foreach (Assistant assistant in assistants) { Console.WriteLine($"[{count,3}] {assistant.Id} {assistant.CreatedAt:s} {assistant.Name}"); diff --git a/.dotnet/tests/Samples/Assistants/Sample04_AllTheTools.cs b/.dotnet/tests/Samples/Assistants/Sample04_AllTheTools.cs index 4645e7fdc..a4c7f318f 100644 --- a/.dotnet/tests/Samples/Assistants/Sample04_AllTheTools.cs +++ b/.dotnet/tests/Samples/Assistants/Sample04_AllTheTools.cs @@ -142,7 +142,7 @@ static string GetNameOfFamilyMember(string relation) // With the run complete, list the messages and display their content if (run.Status == RunStatus.Completed) { - PageableCollection messages + PageableResult messages = client.GetMessages(run.ThreadId, resultOrder: ListOrder.OldestFirst); foreach (ThreadMessage message in messages) @@ -177,7 +177,7 @@ PageableCollection messages #endregion #region List run steps for details about tool calls - PageableCollection runSteps = client.GetRunSteps(run, resultOrder: ListOrder.OldestFirst); + PageableResult runSteps = client.GetRunSteps(run, resultOrder: ListOrder.OldestFirst); foreach (RunStep step in runSteps) { Console.WriteLine($"Run step: {step.Status}"); diff --git a/.dotnet/tests/Samples/Assistants/Sample05_AssistantsWithGpt4oVision.cs b/.dotnet/tests/Samples/Assistants/Sample05_AssistantsWithGpt4oVision.cs index 2d3ebbe96..6bf54e8c1 100644 --- a/.dotnet/tests/Samples/Assistants/Sample05_AssistantsWithGpt4oVision.cs +++ b/.dotnet/tests/Samples/Assistants/Sample05_AssistantsWithGpt4oVision.cs @@ -46,7 +46,7 @@ public void Sample05_AssistantsWithGpt4oVision() } }); - ResultCollection streamingUpdates = assistantClient.CreateRunStreaming( + CollectionResult streamingUpdates = assistantClient.CreateRunStreaming( thread, assistant, new RunCreationOptions() diff --git a/.dotnet/tests/Samples/Assistants/Sample05_AssistantsWithGpt4oVisionAsync.cs b/.dotnet/tests/Samples/Assistants/Sample05_AssistantsWithGpt4oVisionAsync.cs index c0a5dced5..7dad5ed35 100644 --- a/.dotnet/tests/Samples/Assistants/Sample05_AssistantsWithGpt4oVisionAsync.cs +++ b/.dotnet/tests/Samples/Assistants/Sample05_AssistantsWithGpt4oVisionAsync.cs @@ -46,7 +46,7 @@ public async Task Sample05_AssistantsWithGpt4oVisionAsync() } }); - AsyncResultCollection streamingUpdates = assistantClient.CreateRunStreamingAsync( + AsyncCollectionResult streamingUpdates = assistantClient.CreateRunStreamingAsync( thread, assistant, new RunCreationOptions() diff --git a/.dotnet/tests/Samples/Chat/Sample02_SimpleChatStreaming.cs b/.dotnet/tests/Samples/Chat/Sample02_SimpleChatStreaming.cs index 85d2a1371..566def69d 100644 --- a/.dotnet/tests/Samples/Chat/Sample02_SimpleChatStreaming.cs +++ b/.dotnet/tests/Samples/Chat/Sample02_SimpleChatStreaming.cs @@ -16,7 +16,7 @@ public void Sample02_SimpleChatStreaming() // This is the default key used and the line can be omitted Environment.GetEnvironmentVariable("OPENAI_API_KEY")); - ResultCollection chatUpdates = client.CompleteChatStreaming( + CollectionResult chatUpdates = client.CompleteChatStreaming( [ new UserChatMessage("Say 'this is a test.'"), ]); diff --git a/.dotnet/tests/Samples/Chat/Sample02_SimpleChatStreamingAsync.cs b/.dotnet/tests/Samples/Chat/Sample02_SimpleChatStreamingAsync.cs index fb108cbee..c11669528 100644 --- a/.dotnet/tests/Samples/Chat/Sample02_SimpleChatStreamingAsync.cs +++ b/.dotnet/tests/Samples/Chat/Sample02_SimpleChatStreamingAsync.cs @@ -17,7 +17,7 @@ public async Task Sample02_SimpleChatStreamingAsync() // This is the default key used and the line can be omitted Environment.GetEnvironmentVariable("OPENAI_API_KEY")); - AsyncResultCollection asyncChatUpdates + AsyncCollectionResult asyncChatUpdates = client.CompleteChatStreamingAsync( [ new UserChatMessage("Say 'this is a test.'"), diff --git a/.dotnet/tests/Samples/Chat/Sample04_FunctionCallingStreaming.cs b/.dotnet/tests/Samples/Chat/Sample04_FunctionCallingStreaming.cs index 675c7b91b..873b050b2 100644 --- a/.dotnet/tests/Samples/Chat/Sample04_FunctionCallingStreaming.cs +++ b/.dotnet/tests/Samples/Chat/Sample04_FunctionCallingStreaming.cs @@ -42,7 +42,7 @@ public void Sample04_FunctionCallingStreaming() Dictionary indexToFunctionName = []; Dictionary indexToFunctionArguments = []; StringBuilder contentBuilder = new(); - ResultCollection chatUpdates + CollectionResult chatUpdates = client.CompleteChatStreaming(messages, options); foreach (StreamingChatCompletionUpdate chatUpdate in chatUpdates) diff --git a/.dotnet/tests/Samples/Chat/Sample04_FunctionCallingStreamingAsync.cs b/.dotnet/tests/Samples/Chat/Sample04_FunctionCallingStreamingAsync.cs index a5665cb4d..396a69ed3 100644 --- a/.dotnet/tests/Samples/Chat/Sample04_FunctionCallingStreamingAsync.cs +++ b/.dotnet/tests/Samples/Chat/Sample04_FunctionCallingStreamingAsync.cs @@ -43,7 +43,7 @@ public async Task Sample04_FunctionCallingStreamingAsync() Dictionary indexToFunctionName = []; Dictionary indexToFunctionArguments = []; StringBuilder contentBuilder = new(); - AsyncResultCollection chatUpdates + AsyncCollectionResult chatUpdates = client.CompleteChatStreamingAsync(messages, options); await foreach (StreamingChatCompletionUpdate chatUpdate in chatUpdates) diff --git a/.dotnet/tests/TestScenarios/Assistants/AssistantTests.cs b/.dotnet/tests/TestScenarios/Assistants/AssistantTests.cs index 8e1ab3519..cfd3bf190 100644 --- a/.dotnet/tests/TestScenarios/Assistants/AssistantTests.cs +++ b/.dotnet/tests/TestScenarios/Assistants/AssistantTests.cs @@ -51,7 +51,7 @@ public void BasicAssistantOperationsWork() }, }); Assert.That(modifiedAssistant.Id, Is.EqualTo(assistant.Id)); - PageableCollection recentAssistants = client.GetAssistants(); + PageableResult recentAssistants = client.GetAssistants(); Assistant listedAssistant = recentAssistants.FirstOrDefault(pageItem => pageItem.Id == assistant.Id); Assert.That(listedAssistant, Is.Not.Null); Assert.That(listedAssistant.Metadata.TryGetValue(s_cleanupMetadataKey, out string newMetadataValue) && newMetadataValue == "goodbye!"); @@ -128,7 +128,7 @@ public void BasicMessageOperationsWork() }); Assert.That(message.Metadata.TryGetValue("messageMetadata", out metadataValue) && metadataValue == "newValue"); - PageableCollection messagePage = client.GetMessages(thread); + PageableResult messagePage = client.GetMessages(thread); Assert.That(messagePage.Count, Is.EqualTo(1)); Assert.That(messagePage.First().Id, Is.EqualTo(message.Id)); Assert.That(messagePage.First().Metadata.TryGetValue("messageMetadata", out metadataValue) && metadataValue == "newValue"); @@ -158,16 +158,16 @@ public void ThreadWithInitialMessagesWorks() }; AssistantThread thread = client.CreateThread(options); Validate(thread); - PageableCollection messages = client.GetMessages(thread, resultOrder: ListOrder.OldestFirst); + PageableResult messages = client.GetMessages(thread, resultOrder: ListOrder.OldestFirst); Assert.That(messages.Count, Is.EqualTo(2)); Assert.That(messages.First().Role, Is.EqualTo(MessageRole.User)); Assert.That(messages.First().Content?.Count, Is.EqualTo(1)); Assert.That(messages.First().Content[0].Text, Is.EqualTo("Hello, world!")); - Assert.That(messages.ElementAt(1).Content?.Count, Is.EqualTo(2)); - Assert.That(messages.ElementAt(1).Content[0], Is.Not.Null); - Assert.That(messages.ElementAt(1).Content[0].Text, Is.EqualTo("Can you describe this image for me?")); - Assert.That(messages.ElementAt(1).Content[1], Is.Not.Null); - Assert.That(messages.ElementAt(1).Content[1].ImageUrl.AbsoluteUri, Is.EqualTo("https://test.openai.com/image.png")); + Assert.That(messages.AsPages().First().Values[1].Content?.Count, Is.EqualTo(2)); + Assert.That(messages.AsPages().First().Values[1].Content[0], Is.Not.Null); + Assert.That(messages.AsPages().First().Values[1].Content[0].Text, Is.EqualTo("Can you describe this image for me?")); + Assert.That(messages.AsPages().First().Values[1].Content[1], Is.Not.Null); + Assert.That(messages.AsPages().First().Values[1].Content[1].ImageUrl.AbsoluteUri, Is.EqualTo("https://test.openai.com/image.png")); } [Test] @@ -178,7 +178,7 @@ public void BasicRunOperationsWork() Validate(assistant); AssistantThread thread = client.CreateThread(); Validate(thread); - PageableCollection runs = client.GetRuns(thread); + PageableResult runs = client.GetRuns(thread); Assert.That(runs.Count, Is.EqualTo(0)); ThreadMessage message = client.CreateMessage(thread.Id, ["Hello, assistant!"]); Validate(message); @@ -192,7 +192,7 @@ public void BasicRunOperationsWork() Assert.That(runs.Count, Is.EqualTo(1)); Assert.That(runs.First().Id, Is.EqualTo(run.Id)); - PageableCollection messages = client.GetMessages(thread); + PageableResult messages = client.GetMessages(thread); Assert.That(messages.Count, Is.GreaterThanOrEqualTo(1)); for (int i = 0; i < 10 && !run.Status.IsTerminal; i++) { @@ -242,7 +242,7 @@ public void BasicRunStepFunctionalityWorks() Assert.That(run.Status, Is.EqualTo(RunStatus.Completed)); Assert.That(run.Usage?.TotalTokens, Is.GreaterThan(0)); - PageableCollection runSteps = client.GetRunSteps(run); + PageableResult runSteps = client.GetRunSteps(run); Assert.That(runSteps.Count, Is.GreaterThan(1)); Assert.Multiple(() => { @@ -361,7 +361,7 @@ public void FunctionToolsWork() } Assert.That(run.Status, Is.EqualTo(RunStatus.Completed)); - PageableCollection messages = client.GetMessages(run.ThreadId, resultOrder: ListOrder.NewestFirst); + PageableResult messages = client.GetMessages(run.ThreadId, resultOrder: ListOrder.NewestFirst); Assert.That(messages.Count, Is.GreaterThan(1)); Assert.That(messages.First().Role, Is.EqualTo(MessageRole.Assistant)); Assert.That(messages.First().Content?[0], Is.Not.Null); @@ -384,7 +384,7 @@ public async Task StreamingRunWorks() Stopwatch stopwatch = Stopwatch.StartNew(); void Print(string message) => Console.WriteLine($"[{stopwatch.ElapsedMilliseconds,6}] {message}"); - AsyncResultCollection streamingResult + AsyncCollectionResult streamingResult = client.CreateRunStreamingAsync(thread.Id, assistant.Id); Print(">>> Connected <<<"); @@ -431,7 +431,7 @@ public async Task StreamingToolCall() void Print(string message) => Console.WriteLine($"[{stopwatch.ElapsedMilliseconds,6}] {message}"); Print(" >>> Beginning call ... "); - AsyncResultCollection asyncResults = client.CreateThreadAndRunStreamingAsync( + AsyncCollectionResult asyncResults = client.CreateThreadAndRunStreamingAsync( assistant, new() { @@ -570,7 +570,7 @@ This file describes the favorite foods of several people. } while (run?.Status.IsTerminal == false); Assert.That(run.Status, Is.EqualTo(RunStatus.Completed)); - PageableCollection messages = client.GetMessages(thread, resultOrder: ListOrder.NewestFirst); + PageableResult messages = client.GetMessages(thread, resultOrder: ListOrder.NewestFirst); foreach (ThreadMessage message in messages) { foreach (MessageContent content in message.Content) @@ -604,10 +604,12 @@ public async Task CanEnumerateAssistants() // Page through collection int count = 0; - AsyncPageableCollection assistants = client.GetAssistantsAsync(ListOrder.NewestFirst); + AsyncPageableResult assistants = client.GetAssistantsAsync(ListOrder.NewestFirst, pageSize: 2); int lastIdSeen = int.MaxValue; + List todelete = new(); + await foreach (Assistant assistant in assistants) { Console.WriteLine($"[{count,3}] {assistant.Id} {assistant.CreatedAt:s} {assistant.Name}"); @@ -616,6 +618,8 @@ public async Task CanEnumerateAssistants() Assert.That(int.TryParse(assistant.Name["Test Assistant ".Length..], out int seenId), Is.True); Assert.That(seenId, Is.LessThan(lastIdSeen)); lastIdSeen = seenId; + + todelete.Add(assistant.Id); } count++; if (lastIdSeen == 0 || count > 100) @@ -624,11 +628,17 @@ public async Task CanEnumerateAssistants() } } + // delete them all! + foreach(var a in todelete) + { + await client.DeleteAssistantAsync(a); + } + Assert.That(count, Is.GreaterThanOrEqualTo(10)); } [Test] - public async Task CanPageThroughAssistantCollection() + public async Task CanEnumerateAssistantsByPage() { AssistantClient client = GetTestClient(); @@ -643,37 +653,280 @@ public async Task CanPageThroughAssistantCollection() Assert.That(assistant.Name, Is.EqualTo($"Test Assistant {i}")); } + // Get a count of the assistants as a baseline. + PageableResult enumerable = client.GetAssistants(ListOrder.NewestFirst, pageSize: 100); + int totalCount = enumerable.Count(); + // Page through collection - int count = 0; + int itemCount = 0; int pageCount = 0; - AsyncPageableCollection assistants = client.GetAssistantsAsync(ListOrder.NewestFirst); - IAsyncEnumerable> pages = assistants.AsPages(pageSizeHint: 2); + AsyncPageableResult assistants = client.GetAssistantsAsync(pageSize: 2, resultOrder: ListOrder.NewestFirst); + IAsyncEnumerable> pages = assistants.AsPages(); - int lastIdSeen = int.MaxValue; + await foreach (PageResult page in pages) + { + foreach (Assistant assistant in page.Values) + { + itemCount++; + } + + pageCount++; + } - await foreach (ResultPage page in pages) + // Counts should equal the number of items and pages we expect. + Assert.That(itemCount, Is.EqualTo(totalCount)); + + // Add one for the last empty page that sets continuation token to null. + Assert.That(pageCount, Is.EqualTo(Math.Ceiling(totalCount / 2.0) + 1)); + } + +#nullable enable + + [Test] + public async Task CanEnumerateAssistantsByPageAndResume() + { + AssistantClient client = GetTestClient(); + + // Create assistant collection + for (int i = 0; i < 10; i++) { - foreach (Assistant assistant in page) + Assistant assistant = client.CreateAssistant("gpt-3.5-turbo", new AssistantCreationOptions() { - Console.WriteLine($"[{count,3}] {assistant.Id} {assistant.CreatedAt:s} {assistant.Name}"); - if (assistant.Name?.StartsWith("Test Assistant ") == true) - { - Assert.That(int.TryParse(assistant.Name["Test Assistant ".Length..], out int seenId), Is.True); - Assert.That(seenId, Is.LessThan(lastIdSeen)); - lastIdSeen = seenId; - } - count++; + Name = $"Test Assistant {i}" + }); + Validate(assistant); + Assert.That(assistant.Name, Is.EqualTo($"Test Assistant {i}")); + } + + // Get a count of the assistants as a baseline. + PageableResult enumerable = client.GetAssistants(ListOrder.NewestFirst, pageSize: 100); + int totalCount = enumerable.Count(); + + // Page through collection + int itemCount = 0; + int pageCount = 0; + AsyncPageableResult assistants = client.GetAssistantsAsync(pageSize: 2, resultOrder: ListOrder.NewestFirst); + IAsyncEnumerable> pages = assistants.AsPages(); + + string? pageToken = default; + + // First iteration - stop after two pages + await foreach (PageResult page in pages) + { + foreach (Assistant assistant in page.Values) + { + itemCount++; } pageCount++; - if (lastIdSeen == 0 || count > 100) + + if (pageCount > 1) { + pageToken = page.NextPageToken; break; } } - Assert.That(count, Is.GreaterThanOrEqualTo(10)); - Assert.That(pageCount, Is.GreaterThanOrEqualTo(5)); + // Second iteration - resume from continuation token. + + // First: call the service method to get the pageable collection. This makes no service calls, + // but sets up the closures needed to replicate the collection from the first call. + assistants = client.GetAssistantsAsync(pageSize: 2, resultOrder: ListOrder.NewestFirst); + + // Next: call AsPages, passing the continuation token we reserved from the previous iteration. + // This does make a service call - it should make a request to the service for the next page + // after where we stopped in the prior iteration. + pages = assistants.AsPages(pageToken); + + // Now iterate again, continuing the counts. + await foreach (PageResult page in pages) + { + foreach (Assistant assistant in page.Values) + { + itemCount++; + } + + pageCount++; + } + + // Counts should equal the number of items and pages we expect. + Assert.That(itemCount, Is.EqualTo(totalCount)); + + // Add one for the last empty page that sets continuation token to null. + Assert.That(pageCount, Is.EqualTo(Math.Ceiling(totalCount / 2.0) + 1)); + } +#nullable disable + + + [Test] + public void CanGetPrevPageWhenEnumeratingPages() + { + AssistantClient client = GetTestClient(); + + //// Create assistant collection + //for (int i = 0; i < 10; i++) + //{ + // Assistant assistant = client.CreateAssistant("gpt-3.5-turbo", new AssistantCreationOptions() + // { + // Name = $"Test Assistant {i}", + // }); + // Validate(assistant); + // Assert.That(assistant.Name, Is.EqualTo($"Test Assistant {i}")); + //} + + //// Get the full list of assistants in the order they were created. + //PageableResult enumerable = client.GetAssistants(ListOrder.OldestFirst, pageSize: 100); + //List assistantList = enumerable.ToList(); + //int totalCount = assistantList.Count; + + // Get the collection in smaller pages so we can traverse the pages. + PageableResult assistants = client.GetAssistants( + ListOrder.OldestFirst, + pageSize: 2); + + IEnumerable> pages = assistants.AsPages(); + + // Get first page + PageResult firstPage = default; + PageResult secondPage = default; + PageResult thirdPage = default; + int pageCount = 0; + foreach (var page in pages) + { + if (pageCount == 0) + { + firstPage = page; + } + + if (pageCount == 1) + { + secondPage = page; + } + + if (pageCount== 2) + { + thirdPage = page; + break; + } + + pageCount++; + } + + // Get previous page (from second page) -- this should be the first page + pages = assistants.AsPages(secondPage.PreviousPageToken); + PageResult secondPrevPage = default; + foreach (var page in pages) + { + secondPrevPage = page; + break; + } + + // Get previous page (from third page) -- this should be the second page + pages = assistants.AsPages(thirdPage.PreviousPageToken); + PageResult thirdPrevPage = default; + foreach (var page in pages) + { + thirdPrevPage = page; + break; + } + + Assert.AreEqual(firstPage.Values[0].Id, secondPrevPage.Values[0].Id); + Assert.AreEqual(firstPage.Values[^1].Id, secondPrevPage.Values[^1].Id); + + Assert.AreEqual(secondPage.Values[0].Id, thirdPrevPage.Values[0].Id); + Assert.AreEqual(secondPage.Values[^1].Id, thirdPrevPage.Values[^1].Id); + + // Because we're constructing this a priori. + Assert.IsNotNull(secondPage.PreviousPageToken); + + // These should both point to the second page + Assert.AreEqual(thirdPage.PreviousPageToken, firstPage.NextPageToken); + } + + + [Test] + public void CanGetPrevPageOfAssistants() + { + AssistantClient client = GetTestClient(); + + //// Create assistant collection + //for (int i = 0; i < 10; i++) + //{ + // Assistant assistant = client.CreateAssistant("gpt-3.5-turbo", new AssistantCreationOptions() + // { + // Name = $"Test Assistant {i}", + // }); + // Validate(assistant); + // Assert.That(assistant.Name, Is.EqualTo($"Test Assistant {i}")); + //} + + //// Get the full list of assistants in the order they were created. + //PageableResult enumerable = client.GetAssistants(ListOrder.OldestFirst, pageSize: 100); + //List assistantList = enumerable.ToList(); + //int totalCount = assistantList.Count; + + // Get the collection in smaller pages so we can traverse the pages. + PageableResult assistants = client.GetAssistants( + ListOrder.OldestFirst, + pageSize: 2); + + IEnumerable> pages = assistants.AsPages(); + + // Get first page + PageResult firstPage = default; + foreach (var page in pages) + { + firstPage = page; + break; + } + + // Get second page + pages = assistants.AsPages(firstPage.NextPageToken); + PageResult secondPage = default; + foreach (var page in pages) + { + secondPage = page; + break; + } + + // Get third page + pages = assistants.AsPages(secondPage.NextPageToken); + PageResult thirdPage = default; + foreach (var page in pages) + { + thirdPage = page; + break; + } + + // Get previous page (from second page) -- this should be the first page + pages = assistants.AsPages(secondPage.PreviousPageToken); + PageResult secondPrevPage = default; + foreach (var page in pages) + { + secondPrevPage = page; + break; + } + + // Get previous page (from third page) -- this should be the second page + pages = assistants.AsPages(thirdPage.PreviousPageToken); + PageResult thirdPrevPage = default; + foreach (var page in pages) + { + thirdPrevPage = page; + break; + } + + Assert.AreEqual(firstPage.Values[0].Id, secondPrevPage.Values[0].Id); + Assert.AreEqual(firstPage.Values[^1].Id, secondPrevPage.Values[^1].Id); + + Assert.AreEqual(secondPage.Values[0].Id, thirdPrevPage.Values[0].Id); + Assert.AreEqual(secondPage.Values[^1].Id, thirdPrevPage.Values[^1].Id); + + // Because we're constructing this a priori. + Assert.IsNotNull(secondPage.PreviousPageToken); + + // These should both point to the second page + Assert.AreEqual(thirdPage.PreviousPageToken, firstPage.NextPageToken); } [TearDown] diff --git a/.dotnet/tests/TestScenarios/Assistants/VectorStoreTests.cs b/.dotnet/tests/TestScenarios/Assistants/VectorStoreTests.cs index bd4e4f646..2a0cd1c54 100644 --- a/.dotnet/tests/TestScenarios/Assistants/VectorStoreTests.cs +++ b/.dotnet/tests/TestScenarios/Assistants/VectorStoreTests.cs @@ -102,7 +102,7 @@ public void CanEnumerateVectorStores() int lastIdSeen = int.MaxValue; int count = 0; - foreach (VectorStore vectorStore in client.GetVectorStores(ListOrder.NewestFirst)) + foreach (VectorStore vectorStore in client.GetVectorStores(resultOrder: ListOrder.NewestFirst)) { Assert.That(vectorStore.Id, Is.Not.Null); if (vectorStore.Name?.StartsWith("Test Vector Store ") == true) @@ -139,7 +139,7 @@ public async Task CanEnumerateVectorStoresAsync() int lastIdSeen = int.MaxValue; int count = 0; - await foreach (VectorStore vectorStore in client.GetVectorStoresAsync(ListOrder.NewestFirst)) + await foreach (VectorStore vectorStore in client.GetVectorStoresAsync(resultOrder: ListOrder.NewestFirst)) { Assert.That(vectorStore.Id, Is.Not.Null); if (vectorStore.Name?.StartsWith("Test Vector Store ") == true) diff --git a/.dotnet/tests/TestScenarios/Chat/ChatClientTests.cs b/.dotnet/tests/TestScenarios/Chat/ChatClientTests.cs index ef756fbdd..7a67b0a38 100644 --- a/.dotnet/tests/TestScenarios/Chat/ChatClientTests.cs +++ b/.dotnet/tests/TestScenarios/Chat/ChatClientTests.cs @@ -76,8 +76,8 @@ public void StreamingChat() TimeSpan? latestTokenReceiptTime = null; Stopwatch stopwatch = Stopwatch.StartNew(); - ResultCollection streamingResult = client.CompleteChatStreaming(messages); - Assert.That(streamingResult, Is.InstanceOf>()); + CollectionResult streamingResult = client.CompleteChatStreaming(messages); + Assert.That(streamingResult, Is.InstanceOf>()); int updateCount = 0; foreach (StreamingChatCompletionUpdate chatUpdate in streamingResult) @@ -108,8 +108,8 @@ public async Task StreamingChatAsync() TimeSpan? latestTokenReceiptTime = null; Stopwatch stopwatch = Stopwatch.StartNew(); - AsyncResultCollection streamingResult = client.CompleteChatStreamingAsync(messages); - Assert.That(streamingResult, Is.InstanceOf>()); + AsyncCollectionResult streamingResult = client.CompleteChatStreamingAsync(messages); + Assert.That(streamingResult, Is.InstanceOf>()); int updateCount = 0; ChatTokenUsage usage = null; @@ -338,7 +338,7 @@ public async Task TokenLogProbabilitiesStreaming(bool includeLogProbabilities) options = new(); } - AsyncResultCollection chatCompletionUpdates = client.CompleteChatStreamingAsync(messages, options); + AsyncCollectionResult chatCompletionUpdates = client.CompleteChatStreamingAsync(messages, options); Assert.That(chatCompletionUpdates, Is.Not.Null); await foreach (StreamingChatCompletionUpdate chatCompletionUpdate in chatCompletionUpdates)