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..41649b215 100644 --- a/.dotnet/src/Custom/Assistants/AssistantClient.Convenience.cs +++ b/.dotnet/src/Custom/Assistants/AssistantClient.Convenience.cs @@ -121,41 +121,45 @@ public virtual ClientResult CreateMessage( MessageCreationOptions options = null) => CreateMessage(thread?.Id, content, options); - /// - /// Returns a collection of instances from an existing . - /// - /// The thread to list messages from. - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// A collection of messages that can be enumerated using await foreach. - public virtual AsyncPageableCollection GetMessagesAsync( - AssistantThread thread, - ListOrder? resultOrder = default) - { - Argument.AssertNotNull(thread, nameof(thread)); - - return GetMessagesAsync(thread.Id, resultOrder); - } - - /// - /// Returns a collection of instances from an existing . - /// - /// The thread to list messages from. - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// A collection of messages that can be enumerated using foreach. - public virtual PageableCollection GetMessages( - AssistantThread thread, - ListOrder? resultOrder = default) - { - Argument.AssertNotNull(thread, nameof(thread)); - - return GetMessages(thread.Id, resultOrder); - } + ///// + ///// Returns a collection of instances from an existing . + ///// + ///// The thread to list messages from. + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// A collection of messages that can be enumerated using await foreach. + //public virtual AsyncClientPageable GetMessagesAsync( + // AssistantThread thread, + // int? pageSize = null, + // ListOrder? itemOrder = default) + //{ + // Argument.AssertNotNull(thread, nameof(thread)); + + // return GetMessagesAsync(thread.Id, pageSize, itemOrder); + //} + + ///// + ///// Returns a collection of instances from an existing . + ///// + ///// The thread to list messages from. + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// A collection of messages that can be enumerated using foreach. + //public virtual ClientPageable GetMessages( + // AssistantThread thread, + // ListOrder? itemOrder = null, + // string itemsAfter = default, + // string itemsBefore = default, + // int? pageSize = null) + //{ + // Argument.AssertNotNull(thread, nameof(thread)); + + // return GetMessages(thread.Id, itemOrder, itemsAfter, itemsBefore, pageSize); + //} /// /// Gets an updated instance of an existing . @@ -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 AsyncClientCollection 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 ClientCollection 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 AsyncClientCollection CreateThreadAndRunStreamingAsync( Assistant assistant, ThreadCreationOptions threadOptions = null, RunCreationOptions runOptions = null) @@ -299,47 +303,53 @@ 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 ClientCollection CreateThreadAndRunStreaming( Assistant assistant, ThreadCreationOptions threadOptions = null, RunCreationOptions runOptions = null) => CreateThreadAndRunStreaming(assistant?.Id, threadOptions, runOptions); - /// - /// Returns a collection of instances associated with an existing . - /// - /// The thread that runs in the list should be associated with. - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// A collection of runs that can be enumerated using await foreach. - public virtual AsyncPageableCollection GetRunsAsync( - AssistantThread thread, - ListOrder? resultOrder = default) - { - Argument.AssertNotNull(thread, nameof(thread)); - - return GetRunsAsync(thread.Id, resultOrder); - } - - /// - /// Returns a collection of instances associated with an existing . - /// - /// The thread that runs in the list should be associated with. - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// A collection of runs that can be enumerated using foreach. - public virtual PageableCollection GetRuns( - AssistantThread thread, - ListOrder? resultOrder = default) - { - Argument.AssertNotNull(thread, nameof(thread)); - - return GetRuns(thread.Id, resultOrder); - } + ///// + ///// Returns a collection of instances associated with an existing . + ///// + ///// The thread that runs in the list should be associated with. + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// A collection of runs that can be enumerated using await foreach. + //public virtual AsyncClientPageable GetRunsAsync( + // AssistantThread thread, + // ListOrder? itemOrder = null, + // string itemsAfter = default, + // string itemsBefore = default, + // int? pageSize = null) + //{ + // Argument.AssertNotNull(thread, nameof(thread)); + + // return GetRunsAsync(thread.Id, itemOrder, itemsAfter, itemsBefore, pageSize); + //} + + ///// + ///// Returns a collection of instances associated with an existing . + ///// + ///// The thread that runs in the list should be associated with. + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// A collection of runs that can be enumerated using foreach. + //public virtual ClientPageable GetRuns( + // AssistantThread thread, + // ListOrder? itemOrder = null, + // string itemsAfter = default, + // string itemsBefore = default, + // int? pageSize = null) + //{ + // Argument.AssertNotNull(thread, nameof(thread)); + + // return GetRuns(thread.Id, itemOrder, itemsAfter, itemsBefore, pageSize); + //} /// /// Gets a refreshed instance of an existing . @@ -390,7 +400,7 @@ public virtual ClientResult SubmitToolOutputsToRun( /// /// The tool outputs, corresponding to instances from the run. /// - public virtual AsyncResultCollection SubmitToolOutputsToRunStreamingAsync( + public virtual AsyncClientCollection 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 ClientCollection SubmitToolOutputsToRunStreaming( ThreadRun run, IEnumerable toolOutputs) => SubmitToolOutputsToRunStreaming(run?.ThreadId, run?.Id, toolOutputs); @@ -423,39 +433,45 @@ public virtual Task> CancelRunAsync(ThreadRun run) public virtual ClientResult CancelRun(ThreadRun run) => CancelRun(run?.ThreadId, run?.Id); - /// - /// Gets a collection of instances associated with a . - /// - /// The run to list run steps from. - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// A collection of run steps that can be enumerated using await foreach. - public virtual PageableCollection GetRunSteps( - ThreadRun run, - ListOrder? resultOrder = default) - { - Argument.AssertNotNull(run, nameof(run)); - - return GetRunSteps(run.ThreadId, run.Id, resultOrder); - } - - /// - /// Gets a collection of instances associated with a . - /// - /// The run to list run steps from. - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// A collection of run steps that can be enumerated using foreach. - public virtual AsyncPageableCollection GetRunStepsAsync( - ThreadRun run, - ListOrder? resultOrder = default) - { - Argument.AssertNotNull(run, nameof(run)); - - return GetRunStepsAsync(run.ThreadId, run.Id, resultOrder); - } + ///// + ///// Gets a collection of instances associated with a . + ///// + ///// The run to list run steps from. + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// A collection of run steps that can be enumerated using await foreach. + //public virtual ClientPageable GetRunSteps( + // ThreadRun run, + // ListOrder? itemOrder = null, + // string itemsAfter = default, + // string itemsBefore = default, + // int? pageSize = null) + //{ + // Argument.AssertNotNull(run, nameof(run)); + + // return GetRunSteps(run.ThreadId, run.Id, itemOrder, itemsAfter, itemsBefore, pageSize); + //} + + ///// + ///// Gets a collection of instances associated with a . + ///// + ///// The run to list run steps from. + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// A collection of run steps that can be enumerated using foreach. + //public virtual AsyncClientPageable GetRunStepsAsync( + // ThreadRun run, + // ListOrder? itemOrder = null, + // string itemsAfter = default, + // string itemsBefore = default, + // int? pageSize = null) + //{ + // Argument.AssertNotNull(run, nameof(run)); + + // return GetRunStepsAsync(run.ThreadId, run.Id, itemOrder, itemsAfter, itemsBefore, pageSize); + //} } diff --git a/.dotnet/src/Custom/Assistants/AssistantClient.Protocol.cs b/.dotnet/src/Custom/Assistants/AssistantClient.Protocol.cs index e6912702e..3855ecf9e 100644 --- a/.dotnet/src/Custom/Assistants/AssistantClient.Protocol.cs +++ b/.dotnet/src/Custom/Assistants/AssistantClient.Protocol.cs @@ -63,6 +63,11 @@ public virtual ClientResult CreateAssistant(BinaryContent content, RequestOption /// 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> GetAssistantsPageAsync(int? limit, string order, string after, string before, RequestOptions options) + //{ + // return await AssistantsPage.FromInputsAsync(this, limit, order, after, before, options).ConfigureAwait(false); + //} + public virtual async Task GetAssistantsAsync(int? limit, string order, string after, string before, RequestOptions options) { using PipelineMessage message = CreateGetAssistantsRequest(limit, order, after, before, options); @@ -93,7 +98,14 @@ public virtual async Task GetAssistantsAsync(int? limit, string or /// 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 GetAssistants(int? limit, string order, string after, string before, RequestOptions options) + //public virtual ClientPage GetAssistantsPage(int? limit, string order, string after, string before, RequestOptions options) + //{ + // throw new NotImplementedException(); + // //using PipelineMessage message = CreateGetAssistantsRequest(limit, order, after, before, options); + // //return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); + //} + + public virtual ClientCollection GetAssistants(int? limit, string order, string after, string before, RequestOptions options) { using PipelineMessage message = CreateGetAssistantsRequest(limit, order, after, before, options); return ClientResult.FromResponse(_pipeline.ProcessMessage(message, options)); diff --git a/.dotnet/src/Custom/Assistants/AssistantClient.cs b/.dotnet/src/Custom/Assistants/AssistantClient.cs index 15838592e..4a94bc297 100644 --- a/.dotnet/src/Custom/Assistants/AssistantClient.cs +++ b/.dotnet/src/Custom/Assistants/AssistantClient.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Threading.Tasks; -using static OpenAI.InternalListHelpers; namespace OpenAI.Assistants; @@ -97,34 +96,70 @@ public virtual ClientResult CreateAssistant(string model, AssistantCr return CreateResultFromProtocol(protocolResult, Assistant.FromResponse); } - /// - /// Returns a collection of instances. - /// - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// A collection of assistants that can be enumerated using await foreach. - public virtual AsyncPageableCollection GetAssistantsAsync(ListOrder? resultOrder = null) - { - return CreateAsyncPageable((continuationToken, pageSize) - => GetAssistantsAsync(pageSize, resultOrder?.ToString(), continuationToken, null, null)); - } + ///// + ///// Returns a collection of instances. + ///// + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// A collection of assistants that can be enumerated using await foreach. + //public virtual IAsyncEnumerable GetAssistantsAsync( + // ListOrder? itemOrder = null, + // string itemsAfter = default, + // string itemsBefore = default, + // int? pageSize = null) + //{ + // throw new NotImplementedException(); + // //ClientPage page = GetAssistantsPage(itemOrder, itemsAfter, itemsBefore, pageSize); + // //return page.ToItemCollectionAsync(); + //} /// /// Returns a collection of instances. /// - /// + /// /// The order that results should appear in the list according to their created_at /// timestamp. /// /// A collection of assistants that can be enumerated using foreach. - public virtual PageableCollection GetAssistants(ListOrder? resultOrder = null) + public virtual ClientCollection GetAssistants( + ListOrder? itemOrder = null, + string itemsAfter = default, + string itemsBefore = default, + int? pageSize = null) { - return CreatePageable((continuationToken, pageSize) - => GetAssistants(pageSize, resultOrder?.ToString(), continuationToken, null, null)); + //yield return GetAssistantsPage(itemOrder, itemsAfter, itemsBefore, pageSize); + + ClientPage page = GetAssistantsPage(itemOrder, itemsAfter, itemsBefore, pageSize); + foreach (var item in page.Values) + { + yield return item; + } + //return page.ToItemCollection(); + //foreach (AssistantsPage page in GetAssistantsPage(itemOrder, itemsAfter, itemsBefore, pageSize);) + //{ + // foreach (T value in page.Values) + // { + // yield return value; + // } + //} } + //public virtual ClientPage GetAssistantsPage( + // ListOrder? itemOrder = null, + // string itemsAfter = default, + // string itemsBefore = default, + // int? pageSize = null) + //{ + // return AssistantsPage.FromInputs(this, + // limit: pageSize, + // order: itemOrder?.ToString(), + // after: itemsAfter, + // before: itemsBefore, + // options: null); + //} + /// /// Deletes an existing . /// @@ -308,43 +343,81 @@ public virtual ClientResult CreateMessage( return CreateResultFromProtocol(protocolResult, ThreadMessage.FromResponse); } - /// - /// Returns a collection of instances from an existing . - /// - /// The ID of the thread to list messages from. - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// A collection of messages that can be enumerated using await foreach. - public virtual AsyncPageableCollection GetMessagesAsync( - string threadId, - ListOrder? resultOrder = null) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - - return CreateAsyncPageable((continuationToken, pageSize) - => GetMessagesAsync(threadId, pageSize, resultOrder?.ToString(), continuationToken, null, null)); - } - - /// - /// Returns a collection of instances from an existing . - /// - /// The ID of the thread to list messages from. - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// A collection of messages that can be enumerated using foreach. - public virtual PageableCollection GetMessages( - string threadId, - ListOrder? resultOrder = null) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - - return CreatePageable((continuationToken, pageSize) - => GetMessages(threadId, pageSize, resultOrder?.ToString(), continuationToken, null, null)); - } + ///// + ///// Returns a collection of instances from an existing . + ///// + ///// The ID of the thread to list messages from. + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// A collection of messages that can be enumerated using await foreach. + //public virtual AsyncClientPageable GetMessagesAsync( + // string threadId, + // int? pageSize = null, + // ListOrder? itemOrder = null, + // string itemsAfter = null, + // string itemsBefore = null) + //{ + // Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + + // async Task> getPageAsync(string pageToken) + // { + // string? after = pageToken is ClientPage.DefaultFirstPageToken ? + // itemsAfter : pageToken; + + // ClientResult result = await GetMessagesAsync(threadId, + // limit: pageSize, + // order: itemOrder?.ToString(), + // after: after, + // before: itemsBefore, + // options: null).ConfigureAwait(false); + // PipelineResponse response = result.GetRawResponse(); + // InternalListMessagesResponse list = ModelReaderWriter.Read(response.Content)!; + + // return ClientPage.Create(list.Data, response, nextPageToken: list.HasMore ? list.LastId : default); + // } + + // return PageableResultHelpers.Create(getPageAsync); + //} + + ///// + ///// Returns a collection of instances from an existing . + ///// + ///// The ID of the thread to list messages from. + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// A collection of messages that can be enumerated using foreach. + //public virtual ClientPageable GetMessages( + // string threadId, + // ListOrder? itemOrder = null, + // string itemsAfter = default, + // string itemsBefore = default, + // int? pageSize = null) + //{ + // Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + + // ClientPage getPage(string pageToken) + // { + // string? after = pageToken is ClientPage.DefaultFirstPageToken ? + // itemsAfter : pageToken; + + // ClientResult result = GetMessages(threadId, + // limit: pageSize, + // order: itemOrder?.ToString(), + // after: after, + // before: itemsBefore, + // options: null); + // PipelineResponse response = result.GetRawResponse(); + // InternalListMessagesResponse list = ModelReaderWriter.Read(response.Content)!; + + // return ClientPage.Create(list.Data, response, nextPageToken: list.HasMore ? list.LastId : default); + // } + + // return PageableResultHelpers.Create(getPage); + //} /// /// Gets an existing from a known . @@ -491,7 +564,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 AsyncClientCollection CreateRunStreamingAsync( string threadId, string assistantId, RunCreationOptions options = null) @@ -517,7 +590,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 ClientCollection CreateRunStreaming( string threadId, string assistantId, RunCreationOptions options = null) @@ -578,7 +651,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 AsyncClientCollection CreateThreadAndRunStreamingAsync( string assistantId, ThreadCreationOptions threadOptions = null, RunCreationOptions runOptions = null) @@ -589,7 +662,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 +675,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 ClientCollection CreateThreadAndRunStreaming( string assistantId, ThreadCreationOptions threadOptions = null, RunCreationOptions runOptions = null) @@ -618,43 +691,82 @@ public virtual ResultCollection CreateThreadAndRunStreaming( return new StreamingUpdateCollection(getResult); } - /// - /// Returns a collection of instances associated with an existing . - /// - /// The ID of the thread that runs in the list should be associated with. - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// A collection of runs that can be enumerated using await foreach. - public virtual AsyncPageableCollection GetRunsAsync( - string threadId, - ListOrder? resultOrder = default) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - - return CreateAsyncPageable((continuationToken, pageSize) - => GetRunsAsync(threadId, pageSize, resultOrder?.ToString(), continuationToken, null, null)); - } - - /// - /// Returns a collection of instances associated with an existing . - /// - /// The ID of the thread that runs in the list should be associated with. - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// A collection of runs that can be enumerated using foreach. - public virtual PageableCollection GetRuns( - string threadId, - ListOrder? resultOrder = default) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - - return CreatePageable((continuationToken, pageSize) - => GetRuns(threadId, pageSize, resultOrder?.ToString(), continuationToken, null, null)); - } + ///// + ///// Returns a collection of instances associated with an existing . + ///// + ///// The ID of the thread that runs in the list should be associated with. + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// A collection of runs that can be enumerated using await foreach. + //public virtual AsyncClientPageable GetRunsAsync( + // string threadId, + // ListOrder? itemOrder = null, + // string itemsAfter = default, + // string itemsBefore = default, + // int? pageSize = null) + //{ + // Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + + // async Task> pageFuncAsync(string pageToken) + // { + // string? after = pageToken is ClientPage.DefaultFirstPageToken ? + // itemsAfter : pageToken; + + // ClientResult result = await GetRunsAsync( + // threadId, + // limit: pageSize, + // order: itemOrder?.ToString(), + // after: after, + // before: itemsBefore, + // options: null).ConfigureAwait(false); + // PipelineResponse response = result.GetRawResponse(); + // InternalListRunsResponse list = ModelReaderWriter.Read(response.Content)!; + + // return ClientPage.Create(list.Data, response, nextPageToken: list.HasMore ? list.LastId : default); + // } + + // return PageableResultHelpers.Create(pageFuncAsync); + //} + + ///// + ///// Returns a collection of instances associated with an existing . + ///// + ///// The ID of the thread that runs in the list should be associated with. + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// A collection of runs that can be enumerated using foreach. + //public virtual ClientPageable GetRuns( + // string threadId, + // ListOrder? itemOrder = null, + // string itemsAfter = default, + // string itemsBefore = default, + // int? pageSize = null) + //{ + // Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + + // ClientPage pageFunc(string pageToken) + // { + // string? after = pageToken is ClientPage.DefaultFirstPageToken ? + // itemsAfter : pageToken; + + // ClientResult result = GetRuns(threadId, + // limit: pageSize, + // order: itemOrder?.ToString(), + // after: after, + // before: itemsBefore, + // options: null); + // PipelineResponse response = result.GetRawResponse(); + // InternalListRunsResponse list = ModelReaderWriter.Read(response.Content)!; + + // return ClientPage.Create(list.Data, response, nextPageToken: list.HasMore ? list.LastId : default); + // } + + // return PageableResultHelpers.Create(pageFunc); + //} /// /// Gets an existing from a known . @@ -739,7 +851,7 @@ public virtual ClientResult SubmitToolOutputsToRun( /// /// The tool outputs, corresponding to instances from the run. /// - public virtual AsyncResultCollection SubmitToolOutputsToRunStreamingAsync( + public virtual AsyncClientCollection SubmitToolOutputsToRunStreamingAsync( string threadId, string runId, IEnumerable toolOutputs) @@ -765,7 +877,7 @@ await SubmitToolOutputsToRunAsync(threadId, runId, content, StreamRequestOptions /// /// The tool outputs, corresponding to instances from the run. /// - public virtual ResultCollection SubmitToolOutputsToRunStreaming( + public virtual ClientCollection SubmitToolOutputsToRunStreaming( string threadId, string runId, IEnumerable toolOutputs) @@ -811,49 +923,87 @@ public virtual ClientResult CancelRun(string threadId, string runId) return CreateResultFromProtocol(protocolResult, ThreadRun.FromResponse); } - /// - /// Gets a collection of instances associated with a . - /// - /// The ID of the thread associated with the run. - /// The ID of the run to list run steps from. - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// A collection of run steps that can be enumerated using await foreach. - public virtual AsyncPageableCollection GetRunStepsAsync( - string threadId, - string runId, - ListOrder? resultOrder = default) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - - return CreateAsyncPageable((continuationToken, pageSize) - => GetRunStepsAsync(threadId, runId, pageSize, resultOrder?.ToString(), continuationToken, null, null)); - } - - /// - /// Gets a collection of instances associated with a . - /// - /// The ID of the thread associated with the run. - /// The ID of the run to list run steps from. - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// A collection of run steps that can be enumerated using foreach. - public virtual PageableCollection GetRunSteps( - string threadId, - string runId, - ListOrder? resultOrder = default) - { - Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); - Argument.AssertNotNullOrEmpty(runId, nameof(runId)); - - return CreatePageable((continuationToken, pageSize) - => GetRunSteps(threadId, runId, pageSize, resultOrder?.ToString(), continuationToken, null, null)); - } + ///// + ///// Gets a collection of instances associated with a . + ///// + ///// The ID of the thread associated with the run. + ///// The ID of the run to list run steps from. + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// A collection of run steps that can be enumerated using await foreach. + //public virtual AsyncClientPageable GetRunStepsAsync( + // string threadId, + // string runId, + // ListOrder? itemOrder = null, + // string itemsAfter = default, + // string itemsBefore = default, + // int? pageSize = null) + //{ + // Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + // Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + + // async Task> pageFuncAsync(string pageToken) + // { + // string? after = pageToken is ClientPage.DefaultFirstPageToken ? + // itemsAfter : pageToken; + + // ClientResult result = await GetRunStepsAsync(threadId, runId, + // limit: pageSize, + // order: itemOrder?.ToString(), + // after: after, + // before: itemsBefore, + // options: null).ConfigureAwait(false); + // PipelineResponse response = result.GetRawResponse(); + // InternalListRunStepsResponse list = ModelReaderWriter.Read(response.Content)!; + + // return ClientPage.Create(list.Data, response, nextPageToken: list.HasMore ? list.LastId : default); + // } + + // return PageableResultHelpers.Create(pageFuncAsync); + //} + + ///// + ///// Gets a collection of instances associated with a . + ///// + ///// The ID of the thread associated with the run. + ///// The ID of the run to list run steps from. + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// A collection of run steps that can be enumerated using foreach. + //public virtual ClientPageable GetRunSteps( + // string threadId, + // string runId, + // ListOrder? itemOrder = null, + // string itemsAfter = default, + // string itemsBefore = default, + // int? pageSize = null) + //{ + // Argument.AssertNotNullOrEmpty(threadId, nameof(threadId)); + // Argument.AssertNotNullOrEmpty(runId, nameof(runId)); + + // ClientPage pageFunc(string pageToken) + // { + // string? after = pageToken is ClientPage.DefaultFirstPageToken ? + // itemsAfter : pageToken; + + // ClientResult result = GetRunSteps(threadId, runId, + // limit: pageSize, + // order: itemOrder?.ToString(), + // after: after, + // before: itemsBefore, + // options: null); + // PipelineResponse response = result.GetRawResponse(); + // InternalListRunStepsResponse list = ModelReaderWriter.Read(response.Content)!; + + // return ClientPage.Create(list.Data, response, nextPageToken: list.HasMore ? list.LastId : default); + // } + + // return PageableResultHelpers.Create(pageFunc); + //} /// /// Gets a single run step from a run. @@ -864,7 +1014,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 +1027,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/AssistantPageableResult.cs b/.dotnet/src/Custom/Assistants/AssistantPageableResult.cs new file mode 100644 index 000000000..cee2148bc --- /dev/null +++ b/.dotnet/src/Custom/Assistants/AssistantPageableResult.cs @@ -0,0 +1,48 @@ +using OpenAI.Assistants; +using System.ClientModel; +using System.ClientModel.Primitives; + +#nullable enable + + +namespace OpenAI; + +//#pragma warning disable OPENAI001 +//internal class AssistantPageableResult : ClientPageable +//{ +// private readonly AssistantClient _client; + +// private readonly ListOrder? _order; +// private readonly string? _after; +// private readonly string? _before; +// private readonly int? _pageSize; + +// public AssistantPageableResult(AssistantClient client, ListOrder? order, string? after, string? before, int? pageSize) +// { +// _client = client; +// _order = order; +// _after = after; +// _before = before; +// _pageSize = pageSize; +// } + +// protected override ClientPage GetPageCore(string pageToken) +// { +// string? after = pageToken is ClientPage.DefaultFirstPageToken ? +// _after : +// pageToken; + +// ClientResult result = _client.GetAssistants( +// limit: _pageSize, +// order: _order?.ToString(), +// after: after, +// before: _before, +// options: null); + +// PipelineResponse response = result.GetRawResponse(); +// InternalListAssistantsResponse list = ModelReaderWriter.Read(response.Content)!; + +// return ClientPage.Create(list.Data, response, nextPageToken: list.HasMore ? list.LastId : default); +// } +//} +//#pragma warning restore OPENAI001 \ No newline at end of file diff --git a/.dotnet/src/Custom/Assistants/AssistantsPage.cs b/.dotnet/src/Custom/Assistants/AssistantsPage.cs new file mode 100644 index 000000000..5ceaabec6 --- /dev/null +++ b/.dotnet/src/Custom/Assistants/AssistantsPage.cs @@ -0,0 +1,98 @@ +using OpenAI.Assistants; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Threading.Tasks; + +#nullable enable + +namespace OpenAI; + +#pragma warning disable OPENAI001 +internal class AssistantsPage : ClientPage +{ + private readonly AssistantClient _client; + + // This is everything I need to request the next page in the collection, + // plus whatever comes back in the response for the next page. + + private readonly int? _limit; + private readonly string? _order; + private readonly string? _after; + private readonly string? _before; + + //Note: you could also do it with a closure if you wanted to + //Func getPageResult, + //Func> getPageResultAsync, + + AssistantsPage(AssistantClient client, + + int? limit, + string? order, + string? after, + string? before, + + IReadOnlyList values, bool hasNext, PipelineResponse response) + : base(values, hasNext, response) + { + _client = client; + + _limit = limit; + _order = order; + _after = after; + _before = before; + } + + public static AssistantsPage FromInputs(AssistantClient client, + int? limit, + string? order, + string? after, + string? before, + RequestOptions? options = null) + { + ClientResult result = client.GetAssistants(limit, order, after, before, options); + PipelineResponse response = result.GetRawResponse(); + InternalListAssistantsResponse list = ModelReaderWriter.Read(response.Content)!; + return new AssistantsPage(client, limit, order, after, before, list.Data, list.HasMore, response); + } + + public static async Task FromInputsAsync(AssistantClient client, + int? limit, + string? order, + string? after, + string? before, + RequestOptions? options = null) + { + ClientResult result = await client.GetAssistantsAsync(limit, order, after, before, options).ConfigureAwait(false); + PipelineResponse response = result.GetRawResponse(); + InternalListAssistantsResponse list = ModelReaderWriter.Read(response.Content)!; + return new AssistantsPage(client, limit, order, after, before, list.Data, list.HasMore, response); + } + + protected override ClientPage GetNext(RequestOptions? options = null) + { + return FromInputs(_client, _limit, _order, _after, _before, options); + } + + protected override async Task> GetNextAsync(RequestOptions? options = null) + { + return await FromInputsAsync(_client, _limit, _order, _after, _before, options).ConfigureAwait(false); + } + + //protected override ClientPage GetNext(RequestOptions? options = null) + //{ + // ClientResult result = _client.GetAssistants(_limit, _order, _after, _before, options); + // PipelineResponse response = result.GetRawResponse(); + // InternalListAssistantsResponse list = ModelReaderWriter.Read(response.Content)!; + // return new AssistantsPage(_client, _limit, _order, _after, _before, list.Data, list.HasMore, response); + //} + + //protected override async Task> GetNextAsync(RequestOptions? options = null) + //{ + // ClientResult result = await _client.GetAssistantsAsync(_limit, _order, _after, _before, options).ConfigureAwait(false); + // PipelineResponse response = result.GetRawResponse(); + // InternalListAssistantsResponse list = ModelReaderWriter.Read(response.Content)!; + // return new AssistantsPage(_client, _limit, _order, _after, _before, list.Data, list.HasMore, response); + //} +} +#pragma warning restore OPENAI001 \ No newline at end of file diff --git a/.dotnet/src/Custom/Assistants/AssistantsProtocolPage.cs b/.dotnet/src/Custom/Assistants/AssistantsProtocolPage.cs new file mode 100644 index 000000000..dc4e9030e --- /dev/null +++ b/.dotnet/src/Custom/Assistants/AssistantsProtocolPage.cs @@ -0,0 +1,83 @@ +using OpenAI.Assistants; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Threading.Tasks; + +//#nullable enable + +//namespace OpenAI; + +//#pragma warning disable OPENAI001 +//internal class AssistantsProtocolPage : ClientPage +//{ +// private readonly AssistantClient _client; + +// // This is everything I need to request the next page in the collection, +// // plus whatever comes back in the response for the next page. + +// private readonly int? _limit; +// private readonly string? _order; +// private readonly string? _after; +// private readonly string? _before; + +// //Note: you could also do it with a closure if you wanted to +// //Func getPageResult, +// //Func> getPageResultAsync, + +// AssistantsProtocolPage(AssistantClient client, + +// int? limit, +// string? order, +// string? after, +// string? before, + +// IReadOnlyList values, bool hasNext, PipelineResponse response) +// : base(values, hasNext, response) +// { +// _client = client; + +// _limit = limit; +// _order = order; +// _after = after; +// _before = before; +// } + +// public static AssistantsPage FromInputs(AssistantClient client, +// int? limit, +// string? order, +// string? after, +// string? before, +// RequestOptions? options = null) +// { +// ClientResult result = client.GetAssistants(limit, order, after, before, options); +// PipelineResponse response = result.GetRawResponse(); +// InternalListAssistantsResponse list = ModelReaderWriter.Read(response.Content)!; +// return new AssistantsPage(client, limit, order, after, before, list.Data, list.HasMore, response); +// } + +// public static async Task FromInputsAsync(AssistantClient client, +// int? limit, +// string? order, +// string? after, +// string? before, +// RequestOptions? options = null) +// { +// ClientResult result = await client.GetAssistantsAsync(limit, order, after, before, options).ConfigureAwait(false); +// PipelineResponse response = result.GetRawResponse(); +// InternalListAssistantsResponse list = ModelReaderWriter.Read(response.Content)!; +// return new AssistantsPage(client, limit, order, after, before, list.Data, list.HasMore, response); +// } + +// protected override ClientPage GetNext(RequestOptions? options = null) +// { +// return FromInputs(_client, _limit, _order, _after, _before, options); +// } + +// protected override async Task> GetNextAsync(RequestOptions? options = null) +// { +// return await FromInputsAsync(_client, _limit, _order, _after, _before, options).ConfigureAwait(false); +// } + +//} +//#pragma warning restore OPENAI001 \ No newline at end of file diff --git a/.dotnet/src/Custom/Assistants/Streaming/AsyncStreamingUpdateCollection.cs b/.dotnet/src/Custom/Assistants/Streaming/AsyncStreamingUpdateCollection.cs index b3f87cf07..ff7375e95 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 : AsyncClientCollection { private readonly Func> _getResultAsync; diff --git a/.dotnet/src/Custom/Assistants/Streaming/StreamingUpdateCollection.cs b/.dotnet/src/Custom/Assistants/Streaming/StreamingUpdateCollection.cs index 4f6e6c943..0630a4cc2 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 : ClientCollection { private readonly Func _getResult; diff --git a/.dotnet/src/Custom/Chat/ChatClient.cs b/.dotnet/src/Custom/Chat/ChatClient.cs index abc04ab5d..c8547396b 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 AsyncClientCollection 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 ClientCollection 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..bc9b4c5b9 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 : AsyncClientCollection { private readonly Func> _getResultAsync; diff --git a/.dotnet/src/Custom/Chat/Internal/StreamingChatCompletionUpdateCollection.cs b/.dotnet/src/Custom/Chat/Internal/StreamingChatCompletionUpdateCollection.cs index fe4546992..5c63f3dab 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 : ClientCollection { private readonly Func _getResult; diff --git a/.dotnet/src/Custom/Common/InternalListHelpers.cs b/.dotnet/src/Custom/Common/InternalListHelpers.cs index 4537ad780..af156c0dd 100644 --- a/.dotnet/src/Custom/Common/InternalListHelpers.cs +++ b/.dotnet/src/Custom/Common/InternalListHelpers.cs @@ -1,37 +1,64 @@ +using OpenAI.Assistants; +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 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 PageableCollection CreatePageable(ListResponseFunc listResponseFunc) - where U : IJsonModel, IInternalListResponse - { - ResultPage pageFunc(string continuationToken, int? pageSize) - => GetPageFromProtocol(listResponseFunc(continuationToken, pageSize)); - return PageableResultHelpers.Create((pageSize) => pageFunc(null, pageSize), pageFunc); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ResultPage GetPageFromProtocol(ClientResult protocolResult) - where UInternalList : IJsonModel, IInternalListResponse - { - PipelineResponse response = protocolResult.GetRawResponse(); - IInternalListResponse values = ModelReaderWriter.Read(response.Content); - return ResultPage.Create(values.Data, values.HasMore ? values.LastId : null, response); - } + internal delegate Task AsyncListResponseFunc(string? pageToken); + internal delegate ClientResult ListResponseFunc(string? pageToken); + + //internal static AsyncClientPageable 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 AsyncClientPageable 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 ClientPageable CreatePageable(ListResponseFunc listResponseFunc) + // where U : IJsonModel, IInternalListResponse + //{ + // ClientPage pageFunc(string? pageToken) + // => GetPageFromProtocol(pageToken, listResponseFunc(pageToken)); + // return PageableResultHelpers.Create(pageFunc, pageFunc); + //} + + //[MethodImpl(MethodImplOptions.AggressiveInlining)] + //private static ClientPage GetPageFromProtocol( + // string? pageToken, ClientResult protocolResult) + // where UInternalList : IJsonModel, IInternalListResponse + //{ + // PageToken token = ToPageToken(pageToken); + + // 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 ClientPage.Create(values.Data, response, + // FromPageToken(nextPageToken), + // FromPageToken(prevPageToken)); + //} + } diff --git a/.dotnet/src/Custom/Common/PageableResultHelpers.cs b/.dotnet/src/Custom/Common/PageableResultHelpers.cs index 23290c932..956b6aa0c 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,75 @@ 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 IAsyncEnumerable Create(Func>> getPageAsync) where T : notnull + // => new FuncAsyncPageable(getPageAsync); - 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 IEnumerable Create(Func> getPage) where T : notnull + // => new FuncPageable(getPage); - private class FuncAsyncPageable : AsyncPageableCollection where T : notnull - { - private readonly Func>> _firstPageFunc; - private readonly Func>>? _nextPageFunc; - private readonly int? _defaultPageSize; - - public FuncAsyncPageable(Func>> firstPageFunc, Func>>? nextPageFunc, int? defaultPageSize = default) - { - _firstPageFunc = firstPageFunc; - _nextPageFunc = nextPageFunc; - _defaultPageSize = defaultPageSize; - } - - public override async IAsyncEnumerable> AsPages(string? continuationToken = default, int? pageSizeHint = default) - { - Func>>? pageFunc = string.IsNullOrEmpty(continuationToken) ? _firstPageFunc : _nextPageFunc; - - if (pageFunc == null) - { - yield break; - } - - int? pageSize = pageSizeHint ?? _defaultPageSize; - do - { - ResultPage page = await pageFunc(continuationToken, pageSize).ConfigureAwait(false); - SetRawResponse(page.GetRawResponse()); - yield return page; - continuationToken = page.ContinuationToken; - pageFunc = _nextPageFunc; - } - while (!string.IsNullOrEmpty(continuationToken) && pageFunc != null); - } - } + ////private class FuncAsyncPageable : IAsyncEnumerable where T : notnull + ////{ + //// private readonly Func>> _getPageAsync; + + //// public FuncAsyncPageable(Func>> getPageAsync) + //// { + //// _getPageAsync = getPageAsync; + //// } - private class FuncPageable : PageableCollection where T : notnull - { - private readonly Func> _firstPageFunc; - private readonly Func>? _nextPageFunc; - private readonly int? _defaultPageSize; - - public FuncPageable(Func> firstPageFunc, Func>? nextPageFunc, int? defaultPageSize = default) - { - _firstPageFunc = firstPageFunc; - _nextPageFunc = nextPageFunc; - _defaultPageSize = defaultPageSize; - } - - public override IEnumerable> AsPages(string? continuationToken = default, int? pageSizeHint = default) - { - Func>? pageFunc = string.IsNullOrEmpty(continuationToken) ? _firstPageFunc : _nextPageFunc; - - if (pageFunc == null) - { - yield break; - } - - int? pageSize = pageSizeHint ?? _defaultPageSize; - do - { - ResultPage page = pageFunc(continuationToken, pageSize); - SetRawResponse(page.GetRawResponse()); - yield return page; - continuationToken = page.ContinuationToken; - pageFunc = _nextPageFunc; - } - while (!string.IsNullOrEmpty(continuationToken) && pageFunc != null); - } + //// protected override async Task> GetPageCoreAsync(string pageToken = "") + //// { + //// return await _getPageAsync(pageToken).ConfigureAwait(false); + //// } + ////} + + //private class PageItemEnumerable : ClientPageable where T : notnull + //{ + // private readonly Func> _getPage; + + // public FuncPageable(Func> getPage) + // { + // _getPage = getPage; + // } + + // protected override ClientPage GetPageCore(string pageToken) + // { + // return _getPage(pageToken); + // } } -} + + //public static AsyncClientPageable Create(Func>> getPageAsync) where T : notnull + // => new FuncAsyncPageable(getPageAsync); + + //public static ClientPageable Create(Func> getPage) where T : notnull + // => new FuncPageable(getPage); + + //private class FuncAsyncPageable : AsyncClientPageable where T : notnull + //{ + // private readonly Func>> _getPageAsync; + + // public FuncAsyncPageable(Func>> getPageAsync) + // { + // _getPageAsync = getPageAsync; + // } + + // protected override async Task> GetPageCoreAsync(string pageToken = "") + // { + // return await _getPageAsync(pageToken).ConfigureAwait(false); + // } + //} + + //private class FuncPageable : ClientPageable where T : notnull + //{ + // private readonly Func> _getPage; + + // public FuncPageable(Func> getPage) + // { + // _getPage = getPage; + // } + + // protected override ClientPage GetPageCore(string pageToken) + // { + // return _getPage(pageToken); + // } + //} +//} diff --git a/.dotnet/src/Custom/VectorStores/VectorStoreClient.Convenience.cs b/.dotnet/src/Custom/VectorStores/VectorStoreClient.Convenience.cs index 3917b5171..ca2ccc19e 100644 --- a/.dotnet/src/Custom/VectorStores/VectorStoreClient.Convenience.cs +++ b/.dotnet/src/Custom/VectorStores/VectorStoreClient.Convenience.cs @@ -80,53 +80,55 @@ public virtual Task> AddFileToVectorSto public virtual ClientResult AddFileToVectorStore(VectorStore vectorStore, OpenAIFileInfo file) => AddFileToVectorStore(vectorStore?.Id, file?.Id); - /// - /// Gets the collection of instances representing file inclusions in the - /// specified vector store. - /// - /// - /// The vector store to enumerate the file associations of. - /// - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// - /// A status filter that file associations must match to be included in the collection. - /// - /// - /// A collection of instances that can be asynchronously enumerated via - /// await foreach. - /// - public virtual AsyncPageableCollection GetFileAssociationsAsync( - VectorStore vectorStore, - ListOrder? resultOrder = null, - VectorStoreFileStatusFilter? filter = null) - => GetFileAssociationsAsync(vectorStore?.Id, resultOrder, filter); + ///// + ///// Gets the collection of instances representing file inclusions in the + ///// specified vector store. + ///// + ///// + ///// The vector store to enumerate the file associations of. + ///// + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// + ///// A status filter that file associations must match to be included in the collection. + ///// + ///// + ///// A collection of instances that can be asynchronously enumerated via + ///// await foreach. + ///// + //public virtual AsyncClientPageable GetFileAssociationsAsync( + // VectorStore vectorStore, + // int? pageSize = null, + // ListOrder? itemOrder = null, + // VectorStoreFileStatusFilter? filter = null) + // => GetFileAssociationsAsync(vectorStore?.Id, pageSize, itemOrder, filter); - /// - /// Gets the collection of instances representing file inclusions in the - /// specified vector store. - /// - /// - /// The ID vector store to enumerate the file associations of. - /// - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// - /// A status filter that file associations must match to be included in the collection. - /// - /// - /// A collection of instances that can be synchronously enumerated via - /// foreach. - /// - public virtual PageableCollection GetFileAssociations( - VectorStore vectorStore, - ListOrder? resultOrder = null, - VectorStoreFileStatusFilter? filter = null) - => GetFileAssociations(vectorStore?.Id, resultOrder); + ///// + ///// Gets the collection of instances representing file inclusions in the + ///// specified vector store. + ///// + ///// + ///// The ID vector store to enumerate the file associations of. + ///// + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// + ///// A status filter that file associations must match to be included in the collection. + ///// + ///// + ///// A collection of instances that can be synchronously enumerated via + ///// foreach. + ///// + //public virtual ClientPageable GetFileAssociations( + // VectorStore vectorStore, + // int? pageSize = null, + // ListOrder? itemOrder = null, + // VectorStoreFileStatusFilter? filter = null) + // => GetFileAssociations(vectorStore?.Id, pageSize, itemOrder); /// /// Gets a instance representing an existing association between a known @@ -228,47 +230,49 @@ public virtual Task> CancelBatchFileJobAsy public virtual ClientResult CancelBatchFileJob(VectorStoreBatchFileJob batchJob) => CancelBatchFileJob(batchJob?.VectorStoreId, batchJob?.BatchId); - /// - /// Gets the 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 order that results should appear in the list according to their created_at - /// timestamp. - /// - /// - /// A status filter that file associations must match to be included in the collection. - /// - /// - /// A collection of instances that can be asynchronously enumerated via - /// await foreach. - /// - public virtual AsyncPageableCollection GetFileAssociationsAsync( - VectorStoreBatchFileJob batchJob, - ListOrder? resultOrder = null, - VectorStoreFileStatusFilter? filter = null) - => GetFileAssociationsAsync(batchJob?.VectorStoreId, batchJob?.BatchId, resultOrder, filter); + ///// + ///// Gets the 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 order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// + ///// A status filter that file associations must match to be included in the collection. + ///// + ///// + ///// A collection of instances that can be asynchronously enumerated via + ///// await foreach. + ///// + //public virtual AsyncClientPageable GetFileAssociationsAsync( + // VectorStoreBatchFileJob batchJob, + // int? pageSize = null, + // ListOrder? itemOrder = null, + // VectorStoreFileStatusFilter? filter = null) + // => GetFileAssociationsAsync(batchJob?.VectorStoreId, batchJob?.BatchId, pageSize, itemOrder, filter); - /// - /// Gets the 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 vector store batch file job to retrieve file associations from. - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// - /// A status filter that file associations must match to be included in the collection. - /// - /// - /// A collection of instances that can be synchronously enumerated via - /// foreach. - /// - public virtual PageableCollection GetFileAssociations( - VectorStoreBatchFileJob batchJob, - ListOrder? resultOrder = null, - VectorStoreFileStatusFilter? filter = null) - => GetFileAssociations(batchJob?.VectorStoreId, batchJob?.BatchId, resultOrder, filter); + ///// + ///// Gets the 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 vector store batch file job to retrieve file associations from. + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// + ///// A status filter that file associations must match to be included in the collection. + ///// + ///// + ///// A collection of instances that can be synchronously enumerated via + ///// foreach. + ///// + //public virtual ClientPageable GetFileAssociations( + // VectorStoreBatchFileJob batchJob, + // int? pageSize = null, + // ListOrder? itemOrder = null, + // VectorStoreFileStatusFilter? filter = null) + // => GetFileAssociations(batchJob?.VectorStoreId, batchJob?.BatchId, pageSize, itemOrder, filter); } diff --git a/.dotnet/src/Custom/VectorStores/VectorStoreClient.cs b/.dotnet/src/Custom/VectorStores/VectorStoreClient.cs index 501076115..8c9e39e8f 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. @@ -127,38 +127,44 @@ public virtual ClientResult DeleteVectorStore(string vectorStoreId) return ClientResult.FromValue(internalResponse.Deleted, rawProtocolResponse); } - /// - /// Gets the collection of instances for the configured organization. - /// - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// - /// A collection of instances that can be asynchronously enumerated via - /// await foreach. - /// - public virtual AsyncPageableCollection GetVectorStoresAsync(ListOrder? resultOrder = null) - { - return CreateAsyncPageable((continuationToken, pageSize) - => GetVectorStoresAsync(pageSize, resultOrder?.ToString(), continuationToken, null, null)); - } - - /// - /// Gets the collection of instances for the configured organization. - /// - /// - /// The order that results should appear in the list according to their created_at - /// timestamp. - /// - /// - /// A collection of instances that can be synchronously enumerated via foreach. - /// - public virtual PageableCollection GetVectorStores(ListOrder? resultOrder = null) - { - return CreatePageable((continuationToken, pageSize) - => GetVectorStores(pageSize, resultOrder?.ToString(), continuationToken, null, null)); - } + ///// + ///// Gets the collection of instances for the configured organization. + ///// + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// + ///// A collection of instances that can be asynchronously enumerated via + ///// await foreach. + ///// + //public virtual AsyncClientPageable GetVectorStoresAsync( + // int? pageSize = null, + // ListOrder? itemOrder = null) + //{ + // throw new NotImplementedException(); + // //return CreateAsyncPageable( + // // pageToken => + // // GetVectorStoresAsync(limit: pageSize, itemOrder?.ToString(), pageToken, null, null)); + //} + + ///// + ///// Gets the collection of instances for the configured organization. + ///// + ///// + ///// The order that results should appear in the list according to their created_at + ///// timestamp. + ///// + ///// + ///// A collection of instances that can be synchronously enumerated via foreach. + ///// + //public virtual ClientPageable GetVectorStores(int? pageSize = null, ListOrder? itemOrder = null) + //{ + // throw new NotImplementedException(); + // //return CreatePageable( + // // pageToken => + // // GetVectorStores(limit: pageSize, itemOrder?.ToString(), pageToken, null, null)); + //} /// /// Associates a single, uploaded file with a vector store, beginning ingestion of the file into the vector store. @@ -201,7 +207,7 @@ public virtual ClientResult AddFileToVectorStore(str /// /// The ID of the vector store to enumerate the file associations of. /// - /// + /// /// The order that results should appear in the list according to their created_at /// timestamp. /// @@ -212,16 +218,20 @@ public virtual ClientResult AddFileToVectorStore(str /// A collection of instances that can be asynchronously enumerated via /// await foreach. /// - public virtual AsyncPageableCollection GetFileAssociationsAsync( - string vectorStoreId, - 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)); - } + //public virtual AsyncClientPageable GetFileAssociationsAsync( + // string vectorStoreId, + // int? pageSize = null, + // ListOrder? itemOrder = null, + // VectorStoreFileStatusFilter? filter = null) + //{ + // throw new NotImplementedException(); + + // //Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + + // //return CreateAsyncPageable( + // // pageToken => + // // GetFileAssociationsAsync(vectorStoreId, limit: pageSize, itemOrder?.ToString(), pageToken, null, filter?.ToString(), null)); + //} /// /// Gets the collection of instances representing file inclusions in the @@ -230,7 +240,7 @@ public virtual AsyncPageableCollection GetFileAssoci /// /// The ID of the vector store to enumerate the file associations of. /// - /// + /// /// The order that results should appear in the list according to their created_at /// timestamp. /// @@ -241,13 +251,17 @@ 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) - { - Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); - return CreatePageable( - (continuationToken, pageSize) => GetFileAssociations( - vectorStoreId, pageSize, resultOrder?.ToString(), continuationToken, null, filter?.ToString(), null)); - } + //public virtual ClientPageable GetFileAssociations(string vectorStoreId, + // int? pageSize = null, + // ListOrder? itemOrder = null, + // VectorStoreFileStatusFilter? filter = null) + //{ + // throw new NotImplementedException(); + // //Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + // //return CreatePageable( + // // pageToken => + // // GetFileAssociations(vectorStoreId, limit: pageSize, itemOrder?.ToString(), pageToken, null, filter?.ToString(), null)); + //} /// /// Gets a instance representing an existing association between a known @@ -447,7 +461,7 @@ public virtual ClientResult CancelBatchFileJob(string v /// /// The ID of the batch file job that was previously scheduled. /// - /// + /// /// The order that results should appear in the list according to their created_at /// timestamp. /// @@ -458,19 +472,22 @@ public virtual ClientResult CancelBatchFileJob(string v /// A collection of instances that can be asynchronously enumerated via /// await foreach. /// - public virtual AsyncPageableCollection GetFileAssociationsAsync( - string vectorStoreId, - string batchJobId, - ListOrder? resultOrder = null, - VectorStoreFileStatusFilter? filter = null) - { - 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)); - } + //public virtual AsyncClientPageable GetFileAssociationsAsync( + // string vectorStoreId, + // string batchJobId, + // int? pageSize = null, + // ListOrder? itemOrder = null, + // VectorStoreFileStatusFilter? filter = null) + //{ + // throw new NotImplementedException(); + + // //Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + // //Argument.AssertNotNullOrEmpty(batchJobId, nameof(batchJobId)); + + // //return CreateAsyncPageable( + // // pageToken + // // => GetFileAssociationsAsync(vectorStoreId, batchJobId, limit: pageSize, itemOrder?.ToString(), pageToken, null, filter?.ToString(), null)); + //} /// /// Gets the collection of file associations associated with a vector store batch file job, representing the files @@ -482,7 +499,7 @@ public virtual AsyncPageableCollection GetFileAssoci /// /// The ID of the batch file job that was previously scheduled. /// - /// + /// /// The order that results should appear in the list according to their created_at /// timestamp. /// @@ -493,17 +510,20 @@ public virtual AsyncPageableCollection GetFileAssoci /// A collection of instances that can be synchronously enumerated via /// foreach. /// - public virtual PageableCollection GetFileAssociations( - string vectorStoreId, - string batchJobId, - ListOrder? resultOrder = null, - VectorStoreFileStatusFilter? filter = null) - { - 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)); - } + //public virtual ClientPageable GetFileAssociations( + // string vectorStoreId, + // string batchJobId, + // int? pageSize = null, + // ListOrder? itemOrder = null, + // VectorStoreFileStatusFilter? filter = null) + //{ + // throw new NotImplementedException(); + + // //Argument.AssertNotNullOrEmpty(vectorStoreId, nameof(vectorStoreId)); + // //Argument.AssertNotNullOrEmpty(batchJobId, nameof(batchJobId)); + + // //return CreatePageable( + // // pageToken => + // // GetFileAssociations(vectorStoreId, batchJobId, limit: pageSize, itemOrder?.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..2b8d3e5b9 100644 --- a/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGeneration.cs +++ b/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGeneration.cs @@ -11,149 +11,149 @@ namespace OpenAI.Samples; public partial class AssistantSamples { - [Test] - [Ignore("Compilation validation only")] - public void Sample01_RetrievalAugmentedGeneration() - { - // Assistants is a beta API and subject to change; acknowledge its experimental status by suppressing - // the matching warning. - #pragma warning disable OPENAI001 - OpenAIClient openAIClient = new( - // This is the default key used and the line can be omitted - Environment.GetEnvironmentVariable("OPENAI_API_KEY")); - FileClient fileClient = openAIClient.GetFileClient(); - AssistantClient assistantClient = openAIClient.GetAssistantClient(); + //[Test] + //[Ignore("Compilation validation only")] + //public void Sample01_RetrievalAugmentedGeneration() + //{ + // // Assistants is a beta API and subject to change; acknowledge its experimental status by suppressing + // // the matching warning. + // #pragma warning disable OPENAI001 + // OpenAIClient openAIClient = new( + // // This is the default key used and the line can be omitted + // Environment.GetEnvironmentVariable("OPENAI_API_KEY")); + // FileClient fileClient = openAIClient.GetFileClient(); + // AssistantClient assistantClient = openAIClient.GetAssistantClient(); - // First, let's contrive a document we'll use retrieval with and upload it. - using Stream document = BinaryData.FromString(""" - { - "description": "This document contains the sale history data for Contoso products.", - "sales": [ - { - "month": "January", - "by_product": { - "113043": 15, - "113045": 12, - "113049": 2 - } - }, - { - "month": "February", - "by_product": { - "113045": 22 - } - }, - { - "month": "March", - "by_product": { - "113045": 16, - "113055": 5 - } - } - ] - } - """).ToStream(); + // // First, let's contrive a document we'll use retrieval with and upload it. + // using Stream document = BinaryData.FromString(""" + // { + // "description": "This document contains the sale history data for Contoso products.", + // "sales": [ + // { + // "month": "January", + // "by_product": { + // "113043": 15, + // "113045": 12, + // "113049": 2 + // } + // }, + // { + // "month": "February", + // "by_product": { + // "113045": 22 + // } + // }, + // { + // "month": "March", + // "by_product": { + // "113045": 16, + // "113055": 5 + // } + // } + // ] + // } + // """).ToStream(); - OpenAIFileInfo salesFile = fileClient.UploadFile( - document, - "monthly_sales.json", - FileUploadPurpose.Assistants); + // OpenAIFileInfo salesFile = fileClient.UploadFile( + // document, + // "monthly_sales.json", + // FileUploadPurpose.Assistants); - // Now, we'll create a client intended to help with that data - AssistantCreationOptions assistantOptions = new() - { - Name = "Example: Contoso sales RAG", - Instructions = - "You are an assistant that looks up sales data and helps visualize the information based" - + " on user queries. When asked to generate a graph, chart, or other visualization, use" - + " the code interpreter tool to do so.", - Tools = - { - new FileSearchToolDefinition(), - new CodeInterpreterToolDefinition(), - }, - ToolResources = new() - { - FileSearch = new() - { - NewVectorStores = - { - new VectorStoreCreationHelper([salesFile.Id]), - } - } - }, - }; + // // Now, we'll create a client intended to help with that data + // AssistantCreationOptions assistantOptions = new() + // { + // Name = "Example: Contoso sales RAG", + // Instructions = + // "You are an assistant that looks up sales data and helps visualize the information based" + // + " on user queries. When asked to generate a graph, chart, or other visualization, use" + // + " the code interpreter tool to do so.", + // Tools = + // { + // new FileSearchToolDefinition(), + // new CodeInterpreterToolDefinition(), + // }, + // ToolResources = new() + // { + // FileSearch = new() + // { + // NewVectorStores = + // { + // new VectorStoreCreationHelper([salesFile.Id]), + // } + // } + // }, + // }; - Assistant assistant = assistantClient.CreateAssistant("gpt-4o", assistantOptions); + // Assistant assistant = assistantClient.CreateAssistant("gpt-4o", assistantOptions); - // Now we'll create a thread with a user query about the data already associated with the assistant, then run it - ThreadCreationOptions threadOptions = new() - { - InitialMessages = - { - new ThreadInitializationMessage(new List() - { - MessageContent.FromText("How well did product 113045 sell in February? Graph its trend over time."), - }), - }, - }; + // // Now we'll create a thread with a user query about the data already associated with the assistant, then run it + // ThreadCreationOptions threadOptions = new() + // { + // InitialMessages = + // { + // new ThreadInitializationMessage(new List() + // { + // MessageContent.FromText("How well did product 113045 sell in February? Graph its trend over time."), + // }), + // }, + // }; - ThreadRun threadRun = assistantClient.CreateThreadAndRun(assistant.Id, threadOptions); + // ThreadRun threadRun = assistantClient.CreateThreadAndRun(assistant.Id, threadOptions); - // Check back to see when the run is done - do - { - Thread.Sleep(TimeSpan.FromSeconds(1)); - threadRun = assistantClient.GetRun(threadRun.ThreadId, threadRun.Id); - } while (!threadRun.Status.IsTerminal); + // // Check back to see when the run is done + // do + // { + // Thread.Sleep(TimeSpan.FromSeconds(1)); + // threadRun = assistantClient.GetRun(threadRun.ThreadId, threadRun.Id); + // } 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); + // // Finally, we'll print out the full history for the thread that includes the augmented generation + // ClientPageable messages + // = assistantClient.GetMessages(threadRun.ThreadId, itemOrder: ListOrder.OldestFirst); - foreach (ThreadMessage message in messages) - { - Console.Write($"[{message.Role.ToString().ToUpper()}]: "); - foreach (MessageContent contentItem in message.Content) - { - if (!string.IsNullOrEmpty(contentItem.Text)) - { - Console.WriteLine($"{contentItem.Text}"); + // foreach (ThreadMessage message in messages) + // { + // Console.Write($"[{message.Role.ToString().ToUpper()}]: "); + // foreach (MessageContent contentItem in message.Content) + // { + // if (!string.IsNullOrEmpty(contentItem.Text)) + // { + // Console.WriteLine($"{contentItem.Text}"); - if (contentItem.TextAnnotations.Count > 0) - { - Console.WriteLine(); - } + // if (contentItem.TextAnnotations.Count > 0) + // { + // Console.WriteLine(); + // } - // Include annotations, if any. - foreach (TextAnnotation annotation in contentItem.TextAnnotations) - { - if (!string.IsNullOrEmpty(annotation.InputFileId)) - { - Console.WriteLine($"* File citation, file ID: {annotation.InputFileId}"); - } - if (!string.IsNullOrEmpty(annotation.OutputFileId)) - { - Console.WriteLine($"* File output, new file ID: {annotation.OutputFileId}"); - } - } - } - if (!string.IsNullOrEmpty(contentItem.ImageFileId)) - { - OpenAIFileInfo imageInfo = fileClient.GetFile(contentItem.ImageFileId); - BinaryData imageBytes = fileClient.DownloadFile(contentItem.ImageFileId); - using FileStream stream = File.OpenWrite($"{imageInfo.Filename}.png"); - imageBytes.ToStream().CopyTo(stream); + // // Include annotations, if any. + // foreach (TextAnnotation annotation in contentItem.TextAnnotations) + // { + // if (!string.IsNullOrEmpty(annotation.InputFileId)) + // { + // Console.WriteLine($"* File citation, file ID: {annotation.InputFileId}"); + // } + // if (!string.IsNullOrEmpty(annotation.OutputFileId)) + // { + // Console.WriteLine($"* File output, new file ID: {annotation.OutputFileId}"); + // } + // } + // } + // if (!string.IsNullOrEmpty(contentItem.ImageFileId)) + // { + // OpenAIFileInfo imageInfo = fileClient.GetFile(contentItem.ImageFileId); + // BinaryData imageBytes = fileClient.DownloadFile(contentItem.ImageFileId); + // using FileStream stream = File.OpenWrite($"{imageInfo.Filename}.png"); + // imageBytes.ToStream().CopyTo(stream); - Console.WriteLine($""); - } - } - Console.WriteLine(); - } + // Console.WriteLine($""); + // } + // } + // Console.WriteLine(); + // } - // Optionally, delete any persistent resources you no longer need. - _ = assistantClient.DeleteThread(threadRun.ThreadId); - _ = assistantClient.DeleteAssistant(assistant); - _ = fileClient.DeleteFile(salesFile); - } + // // Optionally, delete any persistent resources you no longer need. + // _ = assistantClient.DeleteThread(threadRun.ThreadId); + // _ = assistantClient.DeleteAssistant(assistant); + // _ = fileClient.DeleteFile(salesFile); + //} } diff --git a/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGenerationAsync.cs b/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGenerationAsync.cs index 146b16fb5..2e11740f1 100644 --- a/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGenerationAsync.cs +++ b/.dotnet/tests/Samples/Assistants/Sample01_RetrievalAugmentedGenerationAsync.cs @@ -12,149 +12,149 @@ namespace OpenAI.Samples; public partial class AssistantSamples { - [Test] - [Ignore("Compilation validation only")] - public async Task Sample01_RetrievalAugmentedGenerationAsync() - { - // Assistants is a beta API and subject to change; acknowledge its experimental status by suppressing - // the matching warning. - #pragma warning disable OPENAI001 - OpenAIClient openAIClient = new( - // This is the default key used and the line can be omitted - Environment.GetEnvironmentVariable("OPENAI_API_KEY")); - FileClient fileClient = openAIClient.GetFileClient(); - AssistantClient assistantClient = openAIClient.GetAssistantClient(); + //[Test] + //[Ignore("Compilation validation only")] + //public async Task Sample01_RetrievalAugmentedGenerationAsync() + //{ + // // Assistants is a beta API and subject to change; acknowledge its experimental status by suppressing + // // the matching warning. + // #pragma warning disable OPENAI001 + // OpenAIClient openAIClient = new( + // // This is the default key used and the line can be omitted + // Environment.GetEnvironmentVariable("OPENAI_API_KEY")); + // FileClient fileClient = openAIClient.GetFileClient(); + // AssistantClient assistantClient = openAIClient.GetAssistantClient(); - // First, let's contrive a document we'll use retrieval with and upload it. - using Stream document = BinaryData.FromString(""" - { - "description": "This document contains the sale history data for Contoso products.", - "sales": [ - { - "month": "January", - "by_product": { - "113043": 15, - "113045": 12, - "113049": 2 - } - }, - { - "month": "February", - "by_product": { - "113045": 22 - } - }, - { - "month": "March", - "by_product": { - "113045": 16, - "113055": 5 - } - } - ] - } - """).ToStream(); + // // First, let's contrive a document we'll use retrieval with and upload it. + // using Stream document = BinaryData.FromString(""" + // { + // "description": "This document contains the sale history data for Contoso products.", + // "sales": [ + // { + // "month": "January", + // "by_product": { + // "113043": 15, + // "113045": 12, + // "113049": 2 + // } + // }, + // { + // "month": "February", + // "by_product": { + // "113045": 22 + // } + // }, + // { + // "month": "March", + // "by_product": { + // "113045": 16, + // "113055": 5 + // } + // } + // ] + // } + // """).ToStream(); - OpenAIFileInfo salesFile = await fileClient.UploadFileAsync( - document, - "monthly_sales.json", - FileUploadPurpose.Assistants); + // OpenAIFileInfo salesFile = await fileClient.UploadFileAsync( + // document, + // "monthly_sales.json", + // FileUploadPurpose.Assistants); - // Now, we'll create a client intended to help with that data - AssistantCreationOptions assistantOptions = new() - { - Name = "Example: Contoso sales RAG", - Instructions = - "You are an assistant that looks up sales data and helps visualize the information based" - + " on user queries. When asked to generate a graph, chart, or other visualization, use" - + " the code interpreter tool to do so.", - Tools = - { - new FileSearchToolDefinition(), - new CodeInterpreterToolDefinition(), - }, - ToolResources = new() - { - FileSearch = new() - { - NewVectorStores = - { - new VectorStoreCreationHelper([salesFile.Id]), - } - } - }, - }; + // // Now, we'll create a client intended to help with that data + // AssistantCreationOptions assistantOptions = new() + // { + // Name = "Example: Contoso sales RAG", + // Instructions = + // "You are an assistant that looks up sales data and helps visualize the information based" + // + " on user queries. When asked to generate a graph, chart, or other visualization, use" + // + " the code interpreter tool to do so.", + // Tools = + // { + // new FileSearchToolDefinition(), + // new CodeInterpreterToolDefinition(), + // }, + // ToolResources = new() + // { + // FileSearch = new() + // { + // NewVectorStores = + // { + // new VectorStoreCreationHelper([salesFile.Id]), + // } + // } + // }, + // }; - Assistant assistant = await assistantClient.CreateAssistantAsync("gpt-4o", assistantOptions); + // Assistant assistant = await assistantClient.CreateAssistantAsync("gpt-4o", assistantOptions); - // Now we'll create a thread with a user query about the data already associated with the assistant, then run it - ThreadCreationOptions threadOptions = new() - { - InitialMessages = - { - new ThreadInitializationMessage(new List() - { - MessageContent.FromText("How well did product 113045 sell in February? Graph its trend over time."), - }), - }, - }; + // // Now we'll create a thread with a user query about the data already associated with the assistant, then run it + // ThreadCreationOptions threadOptions = new() + // { + // InitialMessages = + // { + // new ThreadInitializationMessage(new List() + // { + // MessageContent.FromText("How well did product 113045 sell in February? Graph its trend over time."), + // }), + // }, + // }; - ThreadRun threadRun = await assistantClient.CreateThreadAndRunAsync(assistant.Id, threadOptions); + // ThreadRun threadRun = await assistantClient.CreateThreadAndRunAsync(assistant.Id, threadOptions); - // Check back to see when the run is done - do - { - Thread.Sleep(TimeSpan.FromSeconds(1)); - threadRun = assistantClient.GetRun(threadRun.ThreadId, threadRun.Id); - } while (!threadRun.Status.IsTerminal); + // // Check back to see when the run is done + // do + // { + // Thread.Sleep(TimeSpan.FromSeconds(1)); + // threadRun = assistantClient.GetRun(threadRun.ThreadId, threadRun.Id); + // } 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); + // // Finally, we'll print out the full history for the thread that includes the augmented generation + // IAsyncEnumerable messages + // = assistantClient.GetMessagesAsync(threadRun.ThreadId, ListOrder.OldestFirst); ; - await foreach (ThreadMessage message in messages) - { - Console.Write($"[{message.Role.ToString().ToUpper()}]: "); - foreach (MessageContent contentItem in message.Content) - { - if (!string.IsNullOrEmpty(contentItem.Text)) - { - Console.WriteLine($"{contentItem.Text}"); + // await foreach (ThreadMessage message in messages) + // { + // Console.Write($"[{message.Role.ToString().ToUpper()}]: "); + // foreach (MessageContent contentItem in message.Content) + // { + // if (!string.IsNullOrEmpty(contentItem.Text)) + // { + // Console.WriteLine($"{contentItem.Text}"); - if (contentItem.TextAnnotations.Count > 0) - { - Console.WriteLine(); - } + // if (contentItem.TextAnnotations.Count > 0) + // { + // Console.WriteLine(); + // } - // Include annotations, if any. - foreach (TextAnnotation annotation in contentItem.TextAnnotations) - { - if (!string.IsNullOrEmpty(annotation.InputFileId)) - { - Console.WriteLine($"* File citation, file ID: {annotation.InputFileId}"); - } - if (!string.IsNullOrEmpty(annotation.OutputFileId)) - { - Console.WriteLine($"* File output, new file ID: {annotation.OutputFileId}"); - } - } - } - if (!string.IsNullOrEmpty(contentItem.ImageFileId)) - { - OpenAIFileInfo imageInfo = await fileClient.GetFileAsync(contentItem.ImageFileId); - BinaryData imageBytes = await fileClient.DownloadFileAsync(contentItem.ImageFileId); - using FileStream stream = File.OpenWrite($"{imageInfo.Filename}.png"); - imageBytes.ToStream().CopyTo(stream); + // // Include annotations, if any. + // foreach (TextAnnotation annotation in contentItem.TextAnnotations) + // { + // if (!string.IsNullOrEmpty(annotation.InputFileId)) + // { + // Console.WriteLine($"* File citation, file ID: {annotation.InputFileId}"); + // } + // if (!string.IsNullOrEmpty(annotation.OutputFileId)) + // { + // Console.WriteLine($"* File output, new file ID: {annotation.OutputFileId}"); + // } + // } + // } + // if (!string.IsNullOrEmpty(contentItem.ImageFileId)) + // { + // OpenAIFileInfo imageInfo = await fileClient.GetFileAsync(contentItem.ImageFileId); + // BinaryData imageBytes = await fileClient.DownloadFileAsync(contentItem.ImageFileId); + // using FileStream stream = File.OpenWrite($"{imageInfo.Filename}.png"); + // imageBytes.ToStream().CopyTo(stream); - Console.WriteLine($""); - } - } - Console.WriteLine(); - } + // Console.WriteLine($""); + // } + // } + // Console.WriteLine(); + // } - // Optionally, delete any persistent resources you no longer need. - _ = await assistantClient.DeleteThreadAsync(threadRun.ThreadId); - _ = await assistantClient.DeleteAssistantAsync(assistant); - _ = await fileClient.DeleteFileAsync(salesFile); - } + // // Optionally, delete any persistent resources you no longer need. + // _ = await assistantClient.DeleteThreadAsync(threadRun.ThreadId); + // _ = await assistantClient.DeleteAssistantAsync(assistant); + // _ = await fileClient.DeleteFileAsync(salesFile); + //} } diff --git a/.dotnet/tests/Samples/Assistants/Sample02_FunctionCalling.cs b/.dotnet/tests/Samples/Assistants/Sample02_FunctionCalling.cs index 7d71e57bd..c6cd9f2b6 100644 --- a/.dotnet/tests/Samples/Assistants/Sample02_FunctionCalling.cs +++ b/.dotnet/tests/Samples/Assistants/Sample02_FunctionCalling.cs @@ -11,185 +11,185 @@ namespace OpenAI.Samples; public partial class AssistantSamples { - [Test] - [Ignore("Compilation validation only")] - public void Sample02_FunctionCalling() - { - #region - string GetCurrentLocation() - { - // Call a location API here. - return "San Francisco"; - } - - const string GetCurrentLocationFunctionName = "get_current_location"; - - FunctionToolDefinition getLocationTool = new() - { - FunctionName = GetCurrentLocationFunctionName, - Description = "Get the user's current location" - }; - - string GetCurrentWeather(string location, string unit = "celsius") - { - // Call a weather API here. - return $"31 {unit}"; - } - - const string GetCurrentWeatherFunctionName = "get_current_weather"; - - FunctionToolDefinition getWeatherTool = new() - { - FunctionName = GetCurrentWeatherFunctionName, - Description = "Get the current weather in a given location", - Parameters = BinaryData.FromString(""" - { - "type": "object", - "properties": { - "location": { - "type": "string", - "description": "The city and state, e.g. Boston, MA" - }, - "unit": { - "type": "string", - "enum": [ "celsius", "fahrenheit" ], - "description": "The temperature unit to use. Infer this from the specified location." - } - }, - "required": [ "location" ] - } - """), - }; - #endregion - - // Assistants is a beta API and subject to change; acknowledge its experimental status by suppressing the matching warning. -#pragma warning disable OPENAI001 - AssistantClient client = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY")); - - #region - // Create an assistant that can call the function tools. - AssistantCreationOptions assistantOptions = new() - { - Name = "Sample: Function Calling", - Instructions = - "Don't make assumptions about what values to plug into functions." - + " Ask for clarification if a user request is ambiguous.", - Tools = { getLocationTool, getWeatherTool }, - }; - - Assistant assistant = client.CreateAssistant("gpt-4-turbo", assistantOptions); - #endregion - - #region - // Create a thread with an initial user message and run it. - ThreadCreationOptions threadOptions = new() - { - InitialMessages = { new ThreadInitializationMessage(["What's the weather like today?"]), }, - }; - - ThreadRun run = client.CreateThreadAndRun(assistant.Id, threadOptions); - #endregion - - #region - // Poll the run until it is no longer queued or in progress. - while (!run.Status.IsTerminal) - { - Thread.Sleep(TimeSpan.FromSeconds(1)); - run = client.GetRun(run.ThreadId, run.Id); - - // If the run requires action, resolve them. - if (run.Status == RunStatus.RequiresAction) - { - List toolOutputs = []; - - foreach (RequiredAction action in run.RequiredActions) - { - switch (action.FunctionName) - { - case GetCurrentLocationFunctionName: - { - string toolResult = GetCurrentLocation(); - toolOutputs.Add(new ToolOutput(action.ToolCallId, toolResult)); - break; - } - - case GetCurrentWeatherFunctionName: - { - // The arguments that the model wants to use to call the function are specified as a - // stringified JSON object based on the schema defined in the tool definition. Note that - // the model may hallucinate arguments too. Consequently, it is important to do the - // appropriate parsing and validation before calling the function. - using JsonDocument argumentsJson = JsonDocument.Parse(action.FunctionArguments); - bool hasLocation = argumentsJson.RootElement.TryGetProperty("location", out JsonElement location); - bool hasUnit = argumentsJson.RootElement.TryGetProperty("unit", out JsonElement unit); - - if (!hasLocation) - { - throw new ArgumentNullException(nameof(location), "The location argument is required."); - } - - string toolResult = hasUnit - ? GetCurrentWeather(location.GetString(), unit.GetString()) - : GetCurrentWeather(location.GetString()); - toolOutputs.Add(new ToolOutput(action.ToolCallId, toolResult)); - break; - } - - default: - { - // Handle other or unexpected calls. - throw new NotImplementedException(); - } - } - } - - // Submit the tool outputs to the assistant, which returns the run to the queued state. - run = client.SubmitToolOutputsToRun(run.ThreadId, run.Id, toolOutputs); - } - } - #endregion - - #region - // With the run complete, list the messages and display their content - if (run.Status == RunStatus.Completed) - { - PageableCollection messages - = client.GetMessages(run.ThreadId, resultOrder: ListOrder.OldestFirst); - - foreach (ThreadMessage message in messages) - { - Console.WriteLine($"[{message.Role.ToString().ToUpper()}]: "); - foreach (MessageContent contentItem in message.Content) - { - Console.WriteLine($"{contentItem.Text}"); - - if (contentItem.ImageFileId is not null) - { - Console.WriteLine($" {contentItem.ImageFileId}"); - } - - // Include annotations, if any. - if (contentItem.TextAnnotations.Count > 0) - { - Console.WriteLine(); - foreach (TextAnnotation annotation in contentItem.TextAnnotations) - { - Console.WriteLine($"* File ID used by file_search: {annotation.InputFileId}"); - Console.WriteLine($"* file_search quote from file: {annotation.InputQuote}"); - Console.WriteLine($"* File ID created by code_interpreter: {annotation.OutputFileId}"); - Console.WriteLine($"* Text to replace: {annotation.TextToReplace}"); - Console.WriteLine($"* Message content index range: {annotation.StartIndex}-{annotation.EndIndex}"); - } - } - - } - Console.WriteLine(); - } - } - else - { - throw new NotImplementedException(run.Status.ToString()); - } - #endregion - } +// [Test] +// [Ignore("Compilation validation only")] +// public void Sample02_FunctionCalling() +// { +// #region +// string GetCurrentLocation() +// { +// // Call a location API here. +// return "San Francisco"; +// } + +// const string GetCurrentLocationFunctionName = "get_current_location"; + +// FunctionToolDefinition getLocationTool = new() +// { +// FunctionName = GetCurrentLocationFunctionName, +// Description = "Get the user's current location" +// }; + +// string GetCurrentWeather(string location, string unit = "celsius") +// { +// // Call a weather API here. +// return $"31 {unit}"; +// } + +// const string GetCurrentWeatherFunctionName = "get_current_weather"; + +// FunctionToolDefinition getWeatherTool = new() +// { +// FunctionName = GetCurrentWeatherFunctionName, +// Description = "Get the current weather in a given location", +// Parameters = BinaryData.FromString(""" +// { +// "type": "object", +// "properties": { +// "location": { +// "type": "string", +// "description": "The city and state, e.g. Boston, MA" +// }, +// "unit": { +// "type": "string", +// "enum": [ "celsius", "fahrenheit" ], +// "description": "The temperature unit to use. Infer this from the specified location." +// } +// }, +// "required": [ "location" ] +// } +// """), +// }; +// #endregion + +// // Assistants is a beta API and subject to change; acknowledge its experimental status by suppressing the matching warning. +//#pragma warning disable OPENAI001 +// AssistantClient client = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY")); + +// #region +// // Create an assistant that can call the function tools. +// AssistantCreationOptions assistantOptions = new() +// { +// Name = "Sample: Function Calling", +// Instructions = +// "Don't make assumptions about what values to plug into functions." +// + " Ask for clarification if a user request is ambiguous.", +// Tools = { getLocationTool, getWeatherTool }, +// }; + +// Assistant assistant = client.CreateAssistant("gpt-4-turbo", assistantOptions); +// #endregion + +// #region +// // Create a thread with an initial user message and run it. +// ThreadCreationOptions threadOptions = new() +// { +// InitialMessages = { new ThreadInitializationMessage(["What's the weather like today?"]), }, +// }; + +// ThreadRun run = client.CreateThreadAndRun(assistant.Id, threadOptions); +// #endregion + +// #region +// // Poll the run until it is no longer queued or in progress. +// while (!run.Status.IsTerminal) +// { +// Thread.Sleep(TimeSpan.FromSeconds(1)); +// run = client.GetRun(run.ThreadId, run.Id); + +// // If the run requires action, resolve them. +// if (run.Status == RunStatus.RequiresAction) +// { +// List toolOutputs = []; + +// foreach (RequiredAction action in run.RequiredActions) +// { +// switch (action.FunctionName) +// { +// case GetCurrentLocationFunctionName: +// { +// string toolResult = GetCurrentLocation(); +// toolOutputs.Add(new ToolOutput(action.ToolCallId, toolResult)); +// break; +// } + +// case GetCurrentWeatherFunctionName: +// { +// // The arguments that the model wants to use to call the function are specified as a +// // stringified JSON object based on the schema defined in the tool definition. Note that +// // the model may hallucinate arguments too. Consequently, it is important to do the +// // appropriate parsing and validation before calling the function. +// using JsonDocument argumentsJson = JsonDocument.Parse(action.FunctionArguments); +// bool hasLocation = argumentsJson.RootElement.TryGetProperty("location", out JsonElement location); +// bool hasUnit = argumentsJson.RootElement.TryGetProperty("unit", out JsonElement unit); + +// if (!hasLocation) +// { +// throw new ArgumentNullException(nameof(location), "The location argument is required."); +// } + +// string toolResult = hasUnit +// ? GetCurrentWeather(location.GetString(), unit.GetString()) +// : GetCurrentWeather(location.GetString()); +// toolOutputs.Add(new ToolOutput(action.ToolCallId, toolResult)); +// break; +// } + +// default: +// { +// // Handle other or unexpected calls. +// throw new NotImplementedException(); +// } +// } +// } + +// // Submit the tool outputs to the assistant, which returns the run to the queued state. +// run = client.SubmitToolOutputsToRun(run.ThreadId, run.Id, toolOutputs); +// } +// } +// #endregion + +// #region +// // With the run complete, list the messages and display their content +// if (run.Status == RunStatus.Completed) +// { +// ClientPageable messages +// = client.GetMessages(run.ThreadId, itemOrder: ListOrder.OldestFirst); + +// foreach (ThreadMessage message in messages) +// { +// Console.WriteLine($"[{message.Role.ToString().ToUpper()}]: "); +// foreach (MessageContent contentItem in message.Content) +// { +// Console.WriteLine($"{contentItem.Text}"); + +// if (contentItem.ImageFileId is not null) +// { +// Console.WriteLine($" {contentItem.ImageFileId}"); +// } + +// // Include annotations, if any. +// if (contentItem.TextAnnotations.Count > 0) +// { +// Console.WriteLine(); +// foreach (TextAnnotation annotation in contentItem.TextAnnotations) +// { +// Console.WriteLine($"* File ID used by file_search: {annotation.InputFileId}"); +// Console.WriteLine($"* file_search quote from file: {annotation.InputQuote}"); +// Console.WriteLine($"* File ID created by code_interpreter: {annotation.OutputFileId}"); +// Console.WriteLine($"* Text to replace: {annotation.TextToReplace}"); +// Console.WriteLine($"* Message content index range: {annotation.StartIndex}-{annotation.EndIndex}"); +// } +// } + +// } +// Console.WriteLine(); +// } +// } +// else +// { +// throw new NotImplementedException(run.Status.ToString()); +// } +// #endregion +// } } diff --git a/.dotnet/tests/Samples/Assistants/Sample02_FunctionCallingAsync.cs b/.dotnet/tests/Samples/Assistants/Sample02_FunctionCallingAsync.cs index 04a8f6b1a..d2d285c35 100644 --- a/.dotnet/tests/Samples/Assistants/Sample02_FunctionCallingAsync.cs +++ b/.dotnet/tests/Samples/Assistants/Sample02_FunctionCallingAsync.cs @@ -11,185 +11,185 @@ namespace OpenAI.Samples; public partial class AssistantSamples { - [Test] - [Ignore("Compilation validation only")] - public async Task Sample02_FunctionCallingAsync() - { - #region - string GetCurrentLocation() - { - // Call a location API here. - return "San Francisco"; - } - - const string GetCurrentLocationFunctionName = "get_current_location"; - - FunctionToolDefinition getLocationTool = new() - { - FunctionName = GetCurrentLocationFunctionName, - Description = "Get the user's current location" - }; - - string GetCurrentWeather(string location, string unit = "celsius") - { - // Call a weather API here. - return $"31 {unit}"; - } - - const string GetCurrentWeatherFunctionName = "get_current_weather"; - - FunctionToolDefinition getWeatherTool = new() - { - FunctionName = GetCurrentWeatherFunctionName, - Description = "Get the current weather in a given location", - Parameters = BinaryData.FromString(""" - { - "type": "object", - "properties": { - "location": { - "type": "string", - "description": "The city and state, e.g. Boston, MA" - }, - "unit": { - "type": "string", - "enum": [ "celsius", "fahrenheit" ], - "description": "The temperature unit to use. Infer this from the specified location." - } - }, - "required": [ "location" ] - } - """), - }; - #endregion - - // Assistants is a beta API and subject to change; acknowledge its experimental status by suppressing the matching warning. -#pragma warning disable OPENAI001 - AssistantClient client = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY")); - - #region - // Create an assistant that can call the function tools. - AssistantCreationOptions assistantOptions = new() - { - Name = "Sample: Function Calling", - Instructions = - "Don't make assumptions about what values to plug into functions." - + " Ask for clarification if a user request is ambiguous.", - Tools = { getLocationTool, getWeatherTool }, - }; - - Assistant assistant = await client.CreateAssistantAsync("gpt-4-turbo", assistantOptions); - #endregion - - #region - // Create a thread with an initial user message and run it. - ThreadCreationOptions threadOptions = new() - { - InitialMessages = { new ThreadInitializationMessage(["What's the weather like today?"]), }, - }; - - ThreadRun run = await client.CreateThreadAndRunAsync(assistant.Id, threadOptions); - #endregion - - #region - // Poll the run until it is no longer queued or in progress. - while (!run.Status.IsTerminal) - { - await Task.Delay(TimeSpan.FromSeconds(1)); - run = await client.GetRunAsync(run.ThreadId, run.Id); - - // If the run requires action, resolve them. - if (run.Status == RunStatus.RequiresAction) - { - List toolOutputs = []; - - foreach (RequiredAction action in run.RequiredActions) - { - switch (action.FunctionName) - { - case GetCurrentLocationFunctionName: - { - string toolResult = GetCurrentLocation(); - toolOutputs.Add(new ToolOutput(action.ToolCallId, toolResult)); - break; - } - - case GetCurrentWeatherFunctionName: - { - // The arguments that the model wants to use to call the function are specified as a - // stringified JSON object based on the schema defined in the tool definition. Note that - // the model may hallucinate arguments too. Consequently, it is important to do the - // appropriate parsing and validation before calling the function. - using JsonDocument argumentsJson = JsonDocument.Parse(action.FunctionArguments); - bool hasLocation = argumentsJson.RootElement.TryGetProperty("location", out JsonElement location); - bool hasUnit = argumentsJson.RootElement.TryGetProperty("unit", out JsonElement unit); - - if (!hasLocation) - { - throw new ArgumentNullException(nameof(location), "The location argument is required."); - } - - string toolResult = hasUnit - ? GetCurrentWeather(location.GetString(), unit.GetString()) - : GetCurrentWeather(location.GetString()); - toolOutputs.Add(new ToolOutput(action.ToolCallId, toolResult)); - break; - } - - default: - { - // Handle other or unexpected calls. - throw new NotImplementedException(); - } - } - } - - // Submit the tool outputs to the assistant, which returns the run to the queued state. - run = await client.SubmitToolOutputsToRunAsync(run.ThreadId, run.Id, toolOutputs); - } - } - #endregion - - #region - // With the run complete, list the messages and display their content - if (run.Status == RunStatus.Completed) - { - AsyncPageableCollection messages - = client.GetMessagesAsync(run.ThreadId, resultOrder: ListOrder.OldestFirst); - - await foreach (ThreadMessage message in messages) - { - Console.WriteLine($"[{message.Role.ToString().ToUpper()}]: "); - foreach (MessageContent contentItem in message.Content) - { - Console.WriteLine($"{contentItem.Text}"); - - if (contentItem.ImageFileId is not null) - { - Console.WriteLine($" {contentItem.ImageFileId}"); - } - - // Include annotations, if any. - if (contentItem.TextAnnotations.Count > 0) - { - Console.WriteLine(); - foreach (TextAnnotation annotation in contentItem.TextAnnotations) - { - Console.WriteLine($"* File ID used by file_search: {annotation.InputFileId}"); - Console.WriteLine($"* file_search quote from file: {annotation.InputQuote}"); - Console.WriteLine($"* File ID created by code_interpreter: {annotation.OutputFileId}"); - Console.WriteLine($"* Text to replace: {annotation.TextToReplace}"); - Console.WriteLine($"* Message content index range: {annotation.StartIndex}-{annotation.EndIndex}"); - } - } - - } - Console.WriteLine(); - } - } - else - { - throw new NotImplementedException(run.Status.ToString()); - } - #endregion - } +// [Test] +// [Ignore("Compilation validation only")] +// public async Task Sample02_FunctionCallingAsync() +// { +// #region +// string GetCurrentLocation() +// { +// // Call a location API here. +// return "San Francisco"; +// } + +// const string GetCurrentLocationFunctionName = "get_current_location"; + +// FunctionToolDefinition getLocationTool = new() +// { +// FunctionName = GetCurrentLocationFunctionName, +// Description = "Get the user's current location" +// }; + +// string GetCurrentWeather(string location, string unit = "celsius") +// { +// // Call a weather API here. +// return $"31 {unit}"; +// } + +// const string GetCurrentWeatherFunctionName = "get_current_weather"; + +// FunctionToolDefinition getWeatherTool = new() +// { +// FunctionName = GetCurrentWeatherFunctionName, +// Description = "Get the current weather in a given location", +// Parameters = BinaryData.FromString(""" +// { +// "type": "object", +// "properties": { +// "location": { +// "type": "string", +// "description": "The city and state, e.g. Boston, MA" +// }, +// "unit": { +// "type": "string", +// "enum": [ "celsius", "fahrenheit" ], +// "description": "The temperature unit to use. Infer this from the specified location." +// } +// }, +// "required": [ "location" ] +// } +// """), +// }; +// #endregion + +// // Assistants is a beta API and subject to change; acknowledge its experimental status by suppressing the matching warning. +//#pragma warning disable OPENAI001 +// AssistantClient client = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY")); + +// #region +// // Create an assistant that can call the function tools. +// AssistantCreationOptions assistantOptions = new() +// { +// Name = "Sample: Function Calling", +// Instructions = +// "Don't make assumptions about what values to plug into functions." +// + " Ask for clarification if a user request is ambiguous.", +// Tools = { getLocationTool, getWeatherTool }, +// }; + +// Assistant assistant = await client.CreateAssistantAsync("gpt-4-turbo", assistantOptions); +// #endregion + +// #region +// // Create a thread with an initial user message and run it. +// ThreadCreationOptions threadOptions = new() +// { +// InitialMessages = { new ThreadInitializationMessage(["What's the weather like today?"]), }, +// }; + +// ThreadRun run = await client.CreateThreadAndRunAsync(assistant.Id, threadOptions); +// #endregion + +// #region +// // Poll the run until it is no longer queued or in progress. +// while (!run.Status.IsTerminal) +// { +// await Task.Delay(TimeSpan.FromSeconds(1)); +// run = await client.GetRunAsync(run.ThreadId, run.Id); + +// // If the run requires action, resolve them. +// if (run.Status == RunStatus.RequiresAction) +// { +// List toolOutputs = []; + +// foreach (RequiredAction action in run.RequiredActions) +// { +// switch (action.FunctionName) +// { +// case GetCurrentLocationFunctionName: +// { +// string toolResult = GetCurrentLocation(); +// toolOutputs.Add(new ToolOutput(action.ToolCallId, toolResult)); +// break; +// } + +// case GetCurrentWeatherFunctionName: +// { +// // The arguments that the model wants to use to call the function are specified as a +// // stringified JSON object based on the schema defined in the tool definition. Note that +// // the model may hallucinate arguments too. Consequently, it is important to do the +// // appropriate parsing and validation before calling the function. +// using JsonDocument argumentsJson = JsonDocument.Parse(action.FunctionArguments); +// bool hasLocation = argumentsJson.RootElement.TryGetProperty("location", out JsonElement location); +// bool hasUnit = argumentsJson.RootElement.TryGetProperty("unit", out JsonElement unit); + +// if (!hasLocation) +// { +// throw new ArgumentNullException(nameof(location), "The location argument is required."); +// } + +// string toolResult = hasUnit +// ? GetCurrentWeather(location.GetString(), unit.GetString()) +// : GetCurrentWeather(location.GetString()); +// toolOutputs.Add(new ToolOutput(action.ToolCallId, toolResult)); +// break; +// } + +// default: +// { +// // Handle other or unexpected calls. +// throw new NotImplementedException(); +// } +// } +// } + +// // Submit the tool outputs to the assistant, which returns the run to the queued state. +// run = await client.SubmitToolOutputsToRunAsync(run.ThreadId, run.Id, toolOutputs); +// } +// } +// #endregion + +// #region +// // With the run complete, list the messages and display their content +// if (run.Status == RunStatus.Completed) +// { +// AsyncClientPageable messages +// = client.GetMessagesAsync(run.ThreadId, itemOrder: ListOrder.OldestFirst); + +// await foreach (ThreadMessage message in messages) +// { +// Console.WriteLine($"[{message.Role.ToString().ToUpper()}]: "); +// foreach (MessageContent contentItem in message.Content) +// { +// Console.WriteLine($"{contentItem.Text}"); + +// if (contentItem.ImageFileId is not null) +// { +// Console.WriteLine($" {contentItem.ImageFileId}"); +// } + +// // Include annotations, if any. +// if (contentItem.TextAnnotations.Count > 0) +// { +// Console.WriteLine(); +// foreach (TextAnnotation annotation in contentItem.TextAnnotations) +// { +// Console.WriteLine($"* File ID used by file_search: {annotation.InputFileId}"); +// Console.WriteLine($"* file_search quote from file: {annotation.InputQuote}"); +// Console.WriteLine($"* File ID created by code_interpreter: {annotation.OutputFileId}"); +// Console.WriteLine($"* Text to replace: {annotation.TextToReplace}"); +// Console.WriteLine($"* Message content index range: {annotation.StartIndex}-{annotation.EndIndex}"); +// } +// } + +// } +// Console.WriteLine(); +// } +// } +// else +// { +// throw new NotImplementedException(run.Status.ToString()); +// } +// #endregion +// } } 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..3e70c4ebe 100644 --- a/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPagination.cs +++ b/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPagination.cs @@ -6,22 +6,22 @@ namespace OpenAI.Samples; public partial class AssistantSamples { - [Test] - [Ignore("Compilation validation only")] - public void Sample03_ListAssistantsWithPagination() - { - // Assistants is a beta API and subject to change; acknowledge its experimental status by suppressing the matching warning. -#pragma warning disable OPENAI001 - AssistantClient client = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY")); +// [Test] +// [Ignore("Compilation validation only")] +// public void Sample03_ListAssistantsWithPagination() +// { +// // Assistants is a beta API and subject to change; acknowledge its experimental status by suppressing the matching warning. +//#pragma warning disable OPENAI001 +// AssistantClient client = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY")); - int count = 0; +// int count = 0; - PageableCollection assistants = client.GetAssistants(); - foreach (Assistant assistant in assistants) - { - Console.WriteLine($"[{count,3}] {assistant.Id} {assistant.CreatedAt:s} {assistant.Name}"); +// ClientPageable assistants = client.GetAssistants(); +// foreach (Assistant assistant in assistants) +// { +// Console.WriteLine($"[{count,3}] {assistant.Id} {assistant.CreatedAt:s} {assistant.Name}"); - count++; - } - } +// count++; +// } +// } } diff --git a/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPaginationAsync.cs b/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPaginationAsync.cs index 3b2122ec9..e12a39752 100644 --- a/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPaginationAsync.cs +++ b/.dotnet/tests/Samples/Assistants/Sample03_ListAssistantsWithPaginationAsync.cs @@ -7,22 +7,22 @@ namespace OpenAI.Samples; public partial class AssistantSamples { - [Test] - [Ignore("Compilation validation only")] - public async Task Sample03_ListAssistantsWithPaginationAsync() - { - // Assistants is a beta API and subject to change; acknowledge its experimental status by suppressing the matching warning. -#pragma warning disable OPENAI001 - AssistantClient client = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY")); +// [Test] +// [Ignore("Compilation validation only")] +// public async Task Sample03_ListAssistantsWithPaginationAsync() +// { +// // Assistants is a beta API and subject to change; acknowledge its experimental status by suppressing the matching warning. +//#pragma warning disable OPENAI001 +// AssistantClient client = new(Environment.GetEnvironmentVariable("OPENAI_API_KEY")); - int count = 0; +// int count = 0; - AsyncPageableCollection assistants = client.GetAssistantsAsync(); - await foreach (Assistant assistant in assistants) - { - Console.WriteLine($"[{count,3}] {assistant.Id} {assistant.CreatedAt:s} {assistant.Name}"); +// AsyncClientPageable assistants = client.GetAssistantsAsync(); +// await foreach (Assistant assistant in assistants) +// { +// Console.WriteLine($"[{count,3}] {assistant.Id} {assistant.CreatedAt:s} {assistant.Name}"); - count++; - } - } +// count++; +// } +// } } diff --git a/.dotnet/tests/Samples/Assistants/Sample04_AllTheTools.cs b/.dotnet/tests/Samples/Assistants/Sample04_AllTheTools.cs index 4645e7fdc..174719908 100644 --- a/.dotnet/tests/Samples/Assistants/Sample04_AllTheTools.cs +++ b/.dotnet/tests/Samples/Assistants/Sample04_AllTheTools.cs @@ -12,196 +12,196 @@ namespace OpenAI.Samples; public partial class AssistantSamples { - [Test] - [Ignore("Only verifying compilation")] - public void Sample04_AllTheTools() - { -#pragma warning disable OPENAI001 - - #region Define a function tool - static string GetNameOfFamilyMember(string relation) - => relation switch - { - { } when relation.Contains("father") => "John Doe", - { } when relation.Contains("mother") => "Jane Doe", - _ => throw new ArgumentException(relation, nameof(relation)) - }; - - FunctionToolDefinition getNameOfFamilyMemberTool = new() - { - FunctionName = nameof(GetNameOfFamilyMember), - Description = "Provided a family relation type like 'father' or 'mother', " - + "gets the name of the related person from the user.", - Parameters = BinaryData.FromString(""" - { - "type": "object", - "properties": { - "relation": { - "type": "string", - "description": "The relation to the user to query, e.g. 'mother' or 'father'" - } - }, - "required": [ "relation" ] - } - """), - }; - - #region Upload a mock file for use with file search - FileClient fileClient = new(); - OpenAIFileInfo favoriteNumberFile = fileClient.UploadFile( - BinaryData.FromString(""" - This file contains the favorite numbers for individuals. - - John Doe: 14 - Bob Doe: 32 - Jane Doe: 44 - """).ToStream(), - "favorite_numbers.txt", - FileUploadPurpose.Assistants); - #endregion - - #region Create an assistant with functions, file search, and code interpreter all enabled - AssistantClient client = new(); - Assistant assistant = client.CreateAssistant("gpt-4-turbo", new AssistantCreationOptions() - { - Instructions = "Use functions to resolve family relations into the names of people. Use file search to " - + " look up the favorite numbers of people. Use code interpreter to create graphs of lines.", - Tools = { getNameOfFamilyMemberTool, new FileSearchToolDefinition(), new CodeInterpreterToolDefinition() }, - ToolResources = new() - { - FileSearch = new() - { - NewVectorStores = - { - new VectorStoreCreationHelper([favoriteNumberFile.Id]), - }, - }, - }, - }); - #endregion - - #region Create a new thread and start a run - AssistantThread thread = client.CreateThread(new ThreadCreationOptions() - { - InitialMessages = - { - new ThreadInitializationMessage( - [ - "Create a graph of a line with a slope that's my father's favorite number " - + "and an offset that's my mother's favorite number.", - "Include people's names in your response and cite where you found them." - ]), - }, - }); - - ThreadRun run = client.CreateRun(thread, assistant); - #endregion - - #region Complete the run, calling functions as needed - // Poll the run until it is no longer queued or in progress. - while (!run.Status.IsTerminal) - { - Thread.Sleep(TimeSpan.FromSeconds(1)); - run = client.GetRun(run.ThreadId, run.Id); - - // If the run requires action, resolve them. - if (run.Status == RunStatus.RequiresAction) - { - List toolOutputs = []; - - foreach (RequiredAction action in run.RequiredActions) - { - switch (action.FunctionName) - { - case nameof(GetNameOfFamilyMember): - { - using JsonDocument argumentsDocument = JsonDocument.Parse(action.FunctionArguments); - string relation = argumentsDocument.RootElement.TryGetProperty("relation", out JsonElement relationProperty) - ? relationProperty.GetString() - : null; - string toolResult = GetNameOfFamilyMember(relation); - toolOutputs.Add(new ToolOutput(action.ToolCallId, toolResult)); - break; - } - - default: - { - // Handle other or unexpected calls. - throw new NotImplementedException(); - } - } - } - - // Submit the tool outputs to the assistant, which returns the run to the queued state. - run = client.SubmitToolOutputsToRun(run.ThreadId, run.Id, toolOutputs); - } - } - #endregion - - #region - // With the run complete, list the messages and display their content - if (run.Status == RunStatus.Completed) - { - PageableCollection messages - = client.GetMessages(run.ThreadId, resultOrder: ListOrder.OldestFirst); - - foreach (ThreadMessage message in messages) - { - Console.WriteLine($"[{message.Role.ToString().ToUpper()}]: "); - foreach (MessageContent contentItem in message.Content) - { - Console.WriteLine($"{contentItem.Text}"); - - if (contentItem.ImageFileId is not null) - { - Console.WriteLine($" {contentItem.ImageFileId}"); - } - - // Include annotations, if any. - if (contentItem.TextAnnotations.Count > 0) - { - Console.WriteLine(); - foreach (TextAnnotation annotation in contentItem.TextAnnotations) - { - Console.WriteLine($"* File ID used by file_search: {annotation.InputFileId}"); - Console.WriteLine($"* file_search quote from file: {annotation.InputQuote}"); - Console.WriteLine($"* File ID created by code_interpreter: {annotation.OutputFileId}"); - Console.WriteLine($"* Text to replace: {annotation.TextToReplace}"); - Console.WriteLine($"* Message content index range: {annotation.StartIndex}-{annotation.EndIndex}"); - } - } - - } - Console.WriteLine(); - } - #endregion - - #region List run steps for details about tool calls - PageableCollection runSteps = client.GetRunSteps(run, resultOrder: ListOrder.OldestFirst); - foreach (RunStep step in runSteps) - { - Console.WriteLine($"Run step: {step.Status}"); - foreach (RunStepToolCall toolCall in step.Details.ToolCalls) - { - Console.WriteLine($" --> Tool call: {toolCall.ToolKind}"); - foreach (RunStepCodeInterpreterOutput output in toolCall.CodeInterpreterOutputs) - { - Console.WriteLine($" --> Output: {output.ImageFileId}"); - } - } - } - #endregion - } - else - { - throw new NotImplementedException(run.Status.ToString()); - } - #endregion - - #region Clean up any temporary resources that are no longer needed - _ = client.DeleteThread(thread); - _ = client.DeleteAssistant(assistant); - _ = fileClient.DeleteFile(favoriteNumberFile.Id); - #endregion - } +// [Test] +// [Ignore("Only verifying compilation")] +// public void Sample04_AllTheTools() +// { +//#pragma warning disable OPENAI001 + +// #region Define a function tool +// static string GetNameOfFamilyMember(string relation) +// => relation switch +// { +// { } when relation.Contains("father") => "John Doe", +// { } when relation.Contains("mother") => "Jane Doe", +// _ => throw new ArgumentException(relation, nameof(relation)) +// }; + +// FunctionToolDefinition getNameOfFamilyMemberTool = new() +// { +// FunctionName = nameof(GetNameOfFamilyMember), +// Description = "Provided a family relation type like 'father' or 'mother', " +// + "gets the name of the related person from the user.", +// Parameters = BinaryData.FromString(""" +// { +// "type": "object", +// "properties": { +// "relation": { +// "type": "string", +// "description": "The relation to the user to query, e.g. 'mother' or 'father'" +// } +// }, +// "required": [ "relation" ] +// } +// """), +// }; + +// #region Upload a mock file for use with file search +// FileClient fileClient = new(); +// OpenAIFileInfo favoriteNumberFile = fileClient.UploadFile( +// BinaryData.FromString(""" +// This file contains the favorite numbers for individuals. + +// John Doe: 14 +// Bob Doe: 32 +// Jane Doe: 44 +// """).ToStream(), +// "favorite_numbers.txt", +// FileUploadPurpose.Assistants); +// #endregion + +// #region Create an assistant with functions, file search, and code interpreter all enabled +// AssistantClient client = new(); +// Assistant assistant = client.CreateAssistant("gpt-4-turbo", new AssistantCreationOptions() +// { +// Instructions = "Use functions to resolve family relations into the names of people. Use file search to " +// + " look up the favorite numbers of people. Use code interpreter to create graphs of lines.", +// Tools = { getNameOfFamilyMemberTool, new FileSearchToolDefinition(), new CodeInterpreterToolDefinition() }, +// ToolResources = new() +// { +// FileSearch = new() +// { +// NewVectorStores = +// { +// new VectorStoreCreationHelper([favoriteNumberFile.Id]), +// }, +// }, +// }, +// }); +// #endregion + +// #region Create a new thread and start a run +// AssistantThread thread = client.CreateThread(new ThreadCreationOptions() +// { +// InitialMessages = +// { +// new ThreadInitializationMessage( +// [ +// "Create a graph of a line with a slope that's my father's favorite number " +// + "and an offset that's my mother's favorite number.", +// "Include people's names in your response and cite where you found them." +// ]), +// }, +// }); + +// ThreadRun run = client.CreateRun(thread, assistant); +// #endregion + +// #region Complete the run, calling functions as needed +// // Poll the run until it is no longer queued or in progress. +// while (!run.Status.IsTerminal) +// { +// Thread.Sleep(TimeSpan.FromSeconds(1)); +// run = client.GetRun(run.ThreadId, run.Id); + +// // If the run requires action, resolve them. +// if (run.Status == RunStatus.RequiresAction) +// { +// List toolOutputs = []; + +// foreach (RequiredAction action in run.RequiredActions) +// { +// switch (action.FunctionName) +// { +// case nameof(GetNameOfFamilyMember): +// { +// using JsonDocument argumentsDocument = JsonDocument.Parse(action.FunctionArguments); +// string relation = argumentsDocument.RootElement.TryGetProperty("relation", out JsonElement relationProperty) +// ? relationProperty.GetString() +// : null; +// string toolResult = GetNameOfFamilyMember(relation); +// toolOutputs.Add(new ToolOutput(action.ToolCallId, toolResult)); +// break; +// } + +// default: +// { +// // Handle other or unexpected calls. +// throw new NotImplementedException(); +// } +// } +// } + +// // Submit the tool outputs to the assistant, which returns the run to the queued state. +// run = client.SubmitToolOutputsToRun(run.ThreadId, run.Id, toolOutputs); +// } +// } +// #endregion + +// #region +// // With the run complete, list the messages and display their content +// if (run.Status == RunStatus.Completed) +// { +// ClientPageable messages +// = client.GetMessages(run.ThreadId, itemOrder: ListOrder.OldestFirst); + +// foreach (ThreadMessage message in messages) +// { +// Console.WriteLine($"[{message.Role.ToString().ToUpper()}]: "); +// foreach (MessageContent contentItem in message.Content) +// { +// Console.WriteLine($"{contentItem.Text}"); + +// if (contentItem.ImageFileId is not null) +// { +// Console.WriteLine($" {contentItem.ImageFileId}"); +// } + +// // Include annotations, if any. +// if (contentItem.TextAnnotations.Count > 0) +// { +// Console.WriteLine(); +// foreach (TextAnnotation annotation in contentItem.TextAnnotations) +// { +// Console.WriteLine($"* File ID used by file_search: {annotation.InputFileId}"); +// Console.WriteLine($"* file_search quote from file: {annotation.InputQuote}"); +// Console.WriteLine($"* File ID created by code_interpreter: {annotation.OutputFileId}"); +// Console.WriteLine($"* Text to replace: {annotation.TextToReplace}"); +// Console.WriteLine($"* Message content index range: {annotation.StartIndex}-{annotation.EndIndex}"); +// } +// } + +// } +// Console.WriteLine(); +// } +// #endregion + +// #region List run steps for details about tool calls +// ClientPageable runSteps = client.GetRunSteps(run, itemOrder: ListOrder.OldestFirst); +// foreach (RunStep step in runSteps) +// { +// Console.WriteLine($"Run step: {step.Status}"); +// foreach (RunStepToolCall toolCall in step.Details.ToolCalls) +// { +// Console.WriteLine($" --> Tool call: {toolCall.ToolKind}"); +// foreach (RunStepCodeInterpreterOutput output in toolCall.CodeInterpreterOutputs) +// { +// Console.WriteLine($" --> Output: {output.ImageFileId}"); +// } +// } +// } +// #endregion +// } +// else +// { +// throw new NotImplementedException(run.Status.ToString()); +// } +// #endregion + +// #region Clean up any temporary resources that are no longer needed +// _ = client.DeleteThread(thread); +// _ = client.DeleteAssistant(assistant); +// _ = fileClient.DeleteFile(favoriteNumberFile.Id); +// #endregion +// } } 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..1175bf7e5 100644 --- a/.dotnet/tests/TestScenarios/Assistants/AssistantTests.cs +++ b/.dotnet/tests/TestScenarios/Assistants/AssistantTests.cs @@ -17,664 +17,893 @@ namespace OpenAI.Tests.Assistants; #pragma warning disable OPENAI001 public partial class AssistantTests { - [Test] - public void BasicAssistantOperationsWork() - { - AssistantClient client = GetTestClient(); - Assistant assistant = client.CreateAssistant("gpt-3.5-turbo"); - Validate(assistant); - Assert.That(assistant.Name, Is.Null.Or.Empty); - assistant = client.ModifyAssistant(assistant.Id, new AssistantModificationOptions() - { - Name = "test assistant name", - }); - Assert.That(assistant.Name, Is.EqualTo("test assistant name")); - bool deleted = client.DeleteAssistant(assistant.Id); - Assert.That(deleted, Is.True); - _assistantsToDelete.Remove(assistant); - assistant = client.CreateAssistant("gpt-3.5-turbo", new AssistantCreationOptions() - { - Metadata = - { - [s_cleanupMetadataKey] = "hello!" - }, - }); - Validate(assistant); - Assistant retrievedAssistant = client.GetAssistant(assistant.Id); - Assert.That(retrievedAssistant.Id, Is.EqualTo(assistant.Id)); - Assert.That(retrievedAssistant.Metadata.TryGetValue(s_cleanupMetadataKey, out string metadataValue) && metadataValue == "hello!"); - Assistant modifiedAssistant = client.ModifyAssistant(assistant.Id, new AssistantModificationOptions() - { - Metadata = - { - [s_cleanupMetadataKey] = "goodbye!", - }, - }); - Assert.That(modifiedAssistant.Id, Is.EqualTo(assistant.Id)); - PageableCollection 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!"); - } - - [Test] - public void BasicThreadOperationsWork() - { - AssistantClient client = GetTestClient(); - AssistantThread thread = client.CreateThread(); - Validate(thread); - Assert.That(thread.CreatedAt, Is.GreaterThan(s_2024)); - bool deleted = client.DeleteThread(thread.Id); - Assert.That(deleted, Is.True); - _threadsToDelete.Remove(thread); - - ThreadCreationOptions options = new() - { - Metadata = - { - ["threadMetadata"] = "threadMetadataValue", - } - }; - thread = client.CreateThread(options); - Validate(thread); - Assert.That(thread.Metadata.TryGetValue("threadMetadata", out string threadMetadataValue) && threadMetadataValue == "threadMetadataValue"); - AssistantThread retrievedThread = client.GetThread(thread.Id); - Assert.That(retrievedThread.Id, Is.EqualTo(thread.Id)); - thread = client.ModifyThread(thread, new ThreadModificationOptions() - { - Metadata = - { - ["threadMetadata"] = "newThreadMetadataValue", - }, - }); - Assert.That(thread.Metadata.TryGetValue("threadMetadata", out threadMetadataValue) && threadMetadataValue == "newThreadMetadataValue"); - } - - [Test] - public void BasicMessageOperationsWork() - { - AssistantClient client = GetTestClient(); - AssistantThread thread = client.CreateThread(); - Validate(thread); - ThreadMessage message = client.CreateMessage(thread, ["Hello, world!"]); - Validate(message); - Assert.That(message.CreatedAt, Is.GreaterThan(s_2024)); - Assert.That(message.Content?.Count, Is.EqualTo(1)); - Assert.That(message.Content[0], Is.Not.Null); - Assert.That(message.Content[0].Text, Is.EqualTo("Hello, world!")); - bool deleted = client.DeleteMessage(message); - Assert.That(deleted, Is.True); - _messagesToDelete.Remove(message); - - message = client.CreateMessage(thread, ["Goodbye, world!"], new MessageCreationOptions() - { - Metadata = - { - ["messageMetadata"] = "messageMetadataValue", - }, - }); - Validate(message); - Assert.That(message.Metadata.TryGetValue("messageMetadata", out string metadataValue) && metadataValue == "messageMetadataValue"); - - ThreadMessage retrievedMessage = client.GetMessage(thread.Id, message.Id); - Assert.That(retrievedMessage.Id, Is.EqualTo(message.Id)); - - message = client.ModifyMessage(message, new MessageModificationOptions() - { - Metadata = - { - ["messageMetadata"] = "newValue", - } - }); - Assert.That(message.Metadata.TryGetValue("messageMetadata", out metadataValue) && metadataValue == "newValue"); - - PageableCollection 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"); - } - - [Test] - public void ThreadWithInitialMessagesWorks() - { - AssistantClient client = GetTestClient(); - ThreadCreationOptions options = new() - { - InitialMessages = - { - new(["Hello, world!"]), - new( - [ - "Can you describe this image for me?", - MessageContent.FromImageUrl(new Uri("https://test.openai.com/image.png")) - ]) - { - Metadata = - { - ["messageMetadata"] = "messageMetadataValue", - }, - }, - }, - }; - AssistantThread thread = client.CreateThread(options); - Validate(thread); - PageableCollection 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")); - } - - [Test] - public void BasicRunOperationsWork() - { - AssistantClient client = GetTestClient(); - Assistant assistant = client.CreateAssistant("gpt-3.5-turbo"); - Validate(assistant); - AssistantThread thread = client.CreateThread(); - Validate(thread); - PageableCollection runs = client.GetRuns(thread); - Assert.That(runs.Count, Is.EqualTo(0)); - ThreadMessage message = client.CreateMessage(thread.Id, ["Hello, assistant!"]); - Validate(message); - ThreadRun run = client.CreateRun(thread.Id, assistant.Id); - Validate(run); - Assert.That(run.Status, Is.EqualTo(RunStatus.Queued)); - Assert.That(run.CreatedAt, Is.GreaterThan(s_2024)); - ThreadRun retrievedRun = client.GetRun(thread.Id, run.Id); - Assert.That(retrievedRun.Id, Is.EqualTo(run.Id)); - runs = client.GetRuns(thread); - Assert.That(runs.Count, Is.EqualTo(1)); - Assert.That(runs.First().Id, Is.EqualTo(run.Id)); - - PageableCollection messages = client.GetMessages(thread); - Assert.That(messages.Count, Is.GreaterThanOrEqualTo(1)); - for (int i = 0; i < 10 && !run.Status.IsTerminal; i++) - { - Thread.Sleep(500); - run = client.GetRun(run); - } - Assert.That(run.Status, Is.EqualTo(RunStatus.Completed)); - Assert.That(run.CompletedAt, Is.GreaterThan(s_2024)); - Assert.That(run.RequiredActions.Count, Is.EqualTo(0)); - Assert.That(run.AssistantId, Is.EqualTo(assistant.Id)); - Assert.That(run.FailedAt, Is.Null); - Assert.That(run.IncompleteDetails, Is.Null); - - messages = client.GetMessages(thread); - Assert.That(messages.Count, Is.EqualTo(2)); - - Assert.That(messages.ElementAt(0).Role, Is.EqualTo(MessageRole.Assistant)); - Assert.That(messages.ElementAt(1).Role, Is.EqualTo(MessageRole.User)); - Assert.That(messages.ElementAt(1).Id, Is.EqualTo(message.Id)); - } - - [Test] - public void BasicRunStepFunctionalityWorks() - { - AssistantClient client = GetTestClient(); - Assistant assistant = client.CreateAssistant("gpt-3.5-turbo", new AssistantCreationOptions() - { - Tools = { new CodeInterpreterToolDefinition() }, - Instructions = "Call the code interpreter tool when asked to visualize mathematical concepts.", - }); - Validate(assistant); - - AssistantThread thread = client.CreateThread(new() - { - InitialMessages = { new(["Please graph the equation y = 3x + 4"]), }, - }); - Validate(thread); - - ThreadRun run = client.CreateRun(thread, assistant); - Validate(run); - - while (!run.Status.IsTerminal) - { - Thread.Sleep(1000); - run = client.GetRun(run); - } - Assert.That(run.Status, Is.EqualTo(RunStatus.Completed)); - Assert.That(run.Usage?.TotalTokens, Is.GreaterThan(0)); - - PageableCollection runSteps = client.GetRunSteps(run); - Assert.That(runSteps.Count, Is.GreaterThan(1)); - Assert.Multiple(() => - { - Assert.That(runSteps.First().AssistantId, Is.EqualTo(assistant.Id)); - Assert.That(runSteps.First().ThreadId, Is.EqualTo(thread.Id)); - Assert.That(runSteps.First().RunId, Is.EqualTo(run.Id)); - Assert.That(runSteps.First().CreatedAt, Is.GreaterThan(s_2024)); - Assert.That(runSteps.First().CompletedAt, Is.GreaterThan(s_2024)); - }); - RunStepDetails details = runSteps.First().Details; - Assert.That(details?.CreatedMessageId, Is.Not.Null.And.Not.Empty); - - details = runSteps.ElementAt(1).Details; - Assert.Multiple(() => - { - Assert.That(details?.ToolCalls.Count, Is.GreaterThan(0)); - Assert.That(details.ToolCalls[0].ToolKind, Is.EqualTo(RunStepToolCallKind.CodeInterpreter)); - Assert.That(details.ToolCalls[0].ToolCallId, Is.Not.Null.And.Not.Empty); - Assert.That(details.ToolCalls[0].CodeInterpreterInput, Is.Not.Null.And.Not.Empty); - Assert.That(details.ToolCalls[0].CodeInterpreterOutputs?.Count, Is.GreaterThan(0)); - Assert.That(details.ToolCalls[0].CodeInterpreterOutputs[0].ImageFileId, Is.Not.Null.And.Not.Empty); - }); - } - - [Test] - public void SettingResponseFormatWorks() - { - AssistantClient client = GetTestClient(); - Assistant assistant = client.CreateAssistant("gpt-4-turbo", new() - { - ResponseFormat = AssistantResponseFormat.JsonObject, - }); - Validate(assistant); - Assert.That(assistant.ResponseFormat, Is.EqualTo(AssistantResponseFormat.JsonObject)); - assistant = client.ModifyAssistant(assistant, new() - { - ResponseFormat = AssistantResponseFormat.Text, - }); - Assert.That(assistant.ResponseFormat, Is.EqualTo(AssistantResponseFormat.Text)); - AssistantThread thread = client.CreateThread(); - Validate(thread); - ThreadMessage message = client.CreateMessage(thread, ["Write some JSON for me!"]); - Validate(message); - ThreadRun run = client.CreateRun(thread, assistant, new() - { - ResponseFormat = AssistantResponseFormat.JsonObject, - }); - Validate(run); - Assert.That(run.ResponseFormat, Is.EqualTo(AssistantResponseFormat.JsonObject)); - } - - [Test] - public void FunctionToolsWork() - { - AssistantClient client = GetTestClient(); - Assistant assistant = client.CreateAssistant("gpt-3.5-turbo", new AssistantCreationOptions() - { - Tools = - { - new FunctionToolDefinition() - { - FunctionName = "get_favorite_food_for_day_of_week", - Description = "gets the user's favorite food for a given day of the week, like Tuesday", - Parameters = BinaryData.FromObjectAsJson(new - { - type = "object", - properties = new - { - day_of_week = new - { - type = "string", - description = "a day of the week, like Tuesday or Saturday", - } - } - }), - }, - }, - }); - Validate(assistant); - Assert.That(assistant.Tools?.Count, Is.EqualTo(1)); - - FunctionToolDefinition responseToolDefinition = assistant.Tools[0] as FunctionToolDefinition; - Assert.That(responseToolDefinition?.FunctionName, Is.EqualTo("get_favorite_food_for_day_of_week")); - Assert.That(responseToolDefinition?.Parameters, Is.Not.Null); - - ThreadRun run = client.CreateThreadAndRun( - assistant, - new ThreadCreationOptions() - { - InitialMessages = { new(["What should I eat on Thursday?"]) }, - }, - new RunCreationOptions() - { - AdditionalInstructions = "Call provided tools when appropriate.", - }); - Validate(run); - - for (int i = 0; i < 10 && !run.Status.IsTerminal; i++) - { - Thread.Sleep(500); - run = client.GetRun(run); - } - Assert.That(run.Status, Is.EqualTo(RunStatus.RequiresAction)); - Assert.That(run.RequiredActions?.Count, Is.EqualTo(1)); - Assert.That(run.RequiredActions[0].ToolCallId, Is.Not.Null.And.Not.Empty); - Assert.That(run.RequiredActions[0].FunctionName, Is.EqualTo("get_favorite_food_for_day_of_week")); - Assert.That(run.RequiredActions[0].FunctionArguments, Is.Not.Null.And.Not.Empty); - - run = client.SubmitToolOutputsToRun(run, [new(run.RequiredActions[0].ToolCallId, "tacos")]); - Assert.That(run.Status.IsTerminal, Is.False); - - for (int i = 0; i < 10 && !run.Status.IsTerminal; i++) - { - Thread.Sleep(500); - run = client.GetRun(run); - } - Assert.That(run.Status, Is.EqualTo(RunStatus.Completed)); - - PageableCollection 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); - Assert.That(messages.First().Content[0].Text, Does.Contain("tacos")); - } + //[Test] + //public void BasicAssistantOperationsWork() + //{ + // AssistantClient client = GetTestClient(); + // Assistant assistant = client.CreateAssistant("gpt-3.5-turbo"); + // Validate(assistant); + // Assert.That(assistant.Name, Is.Null.Or.Empty); + // assistant = client.ModifyAssistant(assistant.Id, new AssistantModificationOptions() + // { + // Name = "test assistant name", + // }); + // Assert.That(assistant.Name, Is.EqualTo("test assistant name")); + // bool deleted = client.DeleteAssistant(assistant.Id); + // Assert.That(deleted, Is.True); + // _assistantsToDelete.Remove(assistant); + // assistant = client.CreateAssistant("gpt-3.5-turbo", new AssistantCreationOptions() + // { + // Metadata = + // { + // [s_cleanupMetadataKey] = "hello!" + // }, + // }); + // Validate(assistant); + // Assistant retrievedAssistant = client.GetAssistant(assistant.Id); + // Assert.That(retrievedAssistant.Id, Is.EqualTo(assistant.Id)); + // Assert.That(retrievedAssistant.Metadata.TryGetValue(s_cleanupMetadataKey, out string metadataValue) && metadataValue == "hello!"); + // Assistant modifiedAssistant = client.ModifyAssistant(assistant.Id, new AssistantModificationOptions() + // { + // Metadata = + // { + // [s_cleanupMetadataKey] = "goodbye!", + // }, + // }); + // Assert.That(modifiedAssistant.Id, Is.EqualTo(assistant.Id)); + // ClientPageable 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!"); + //} + + //[Test] + //public void BasicThreadOperationsWork() + //{ + // AssistantClient client = GetTestClient(); + // AssistantThread thread = client.CreateThread(); + // Validate(thread); + // Assert.That(thread.CreatedAt, Is.GreaterThan(s_2024)); + // bool deleted = client.DeleteThread(thread.Id); + // Assert.That(deleted, Is.True); + // _threadsToDelete.Remove(thread); + + // ThreadCreationOptions options = new() + // { + // Metadata = + // { + // ["threadMetadata"] = "threadMetadataValue", + // } + // }; + // thread = client.CreateThread(options); + // Validate(thread); + // Assert.That(thread.Metadata.TryGetValue("threadMetadata", out string threadMetadataValue) && threadMetadataValue == "threadMetadataValue"); + // AssistantThread retrievedThread = client.GetThread(thread.Id); + // Assert.That(retrievedThread.Id, Is.EqualTo(thread.Id)); + // thread = client.ModifyThread(thread, new ThreadModificationOptions() + // { + // Metadata = + // { + // ["threadMetadata"] = "newThreadMetadataValue", + // }, + // }); + // Assert.That(thread.Metadata.TryGetValue("threadMetadata", out threadMetadataValue) && threadMetadataValue == "newThreadMetadataValue"); + //} + + //[Test] + //public void BasicMessageOperationsWork() + //{ + // AssistantClient client = GetTestClient(); + // AssistantThread thread = client.CreateThread(); + // Validate(thread); + // ThreadMessage message = client.CreateMessage(thread, ["Hello, world!"]); + // Validate(message); + // Assert.That(message.CreatedAt, Is.GreaterThan(s_2024)); + // Assert.That(message.Content?.Count, Is.EqualTo(1)); + // Assert.That(message.Content[0], Is.Not.Null); + // Assert.That(message.Content[0].Text, Is.EqualTo("Hello, world!")); + // bool deleted = client.DeleteMessage(message); + // Assert.That(deleted, Is.True); + // _messagesToDelete.Remove(message); + + // message = client.CreateMessage(thread, ["Goodbye, world!"], new MessageCreationOptions() + // { + // Metadata = + // { + // ["messageMetadata"] = "messageMetadataValue", + // }, + // }); + // Validate(message); + // Assert.That(message.Metadata.TryGetValue("messageMetadata", out string metadataValue) && metadataValue == "messageMetadataValue"); + + // ThreadMessage retrievedMessage = client.GetMessage(thread.Id, message.Id); + // Assert.That(retrievedMessage.Id, Is.EqualTo(message.Id)); + + // message = client.ModifyMessage(message, new MessageModificationOptions() + // { + // Metadata = + // { + // ["messageMetadata"] = "newValue", + // } + // }); + // Assert.That(message.Metadata.TryGetValue("messageMetadata", out metadataValue) && metadataValue == "newValue"); + + // ClientPageable 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"); + //} + + //[Test] + //public void ThreadWithInitialMessagesWorks() + //{ + // AssistantClient client = GetTestClient(); + // ThreadCreationOptions options = new() + // { + // InitialMessages = + // { + // new(["Hello, world!"]), + // new( + // [ + // "Can you describe this image for me?", + // MessageContent.FromImageUrl(new Uri("https://test.openai.com/image.png")) + // ]) + // { + // Metadata = + // { + // ["messageMetadata"] = "messageMetadataValue", + // }, + // }, + // }, + // }; + // AssistantThread thread = client.CreateThread(options); + // Validate(thread); + // ClientPageable messages = client.GetMessages(thread, itemOrder: 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.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] + //public void BasicRunOperationsWork() + //{ + // AssistantClient client = GetTestClient(); + // Assistant assistant = client.CreateAssistant("gpt-3.5-turbo"); + // Validate(assistant); + // AssistantThread thread = client.CreateThread(); + // Validate(thread); + // ClientPageable runs = client.GetRuns(thread); + // Assert.That(runs.Count, Is.EqualTo(0)); + // ThreadMessage message = client.CreateMessage(thread.Id, ["Hello, assistant!"]); + // Validate(message); + // ThreadRun run = client.CreateRun(thread.Id, assistant.Id); + // Validate(run); + // Assert.That(run.Status, Is.EqualTo(RunStatus.Queued)); + // Assert.That(run.CreatedAt, Is.GreaterThan(s_2024)); + // ThreadRun retrievedRun = client.GetRun(thread.Id, run.Id); + // Assert.That(retrievedRun.Id, Is.EqualTo(run.Id)); + // runs = client.GetRuns(thread); + // Assert.That(runs.Count, Is.EqualTo(1)); + // Assert.That(runs.First().Id, Is.EqualTo(run.Id)); + + // ClientPageable messages = client.GetMessages(thread); + // Assert.That(messages.Count, Is.GreaterThanOrEqualTo(1)); + // for (int i = 0; i < 10 && !run.Status.IsTerminal; i++) + // { + // Thread.Sleep(500); + // run = client.GetRun(run); + // } + // Assert.That(run.Status, Is.EqualTo(RunStatus.Completed)); + // Assert.That(run.CompletedAt, Is.GreaterThan(s_2024)); + // Assert.That(run.RequiredActions.Count, Is.EqualTo(0)); + // Assert.That(run.AssistantId, Is.EqualTo(assistant.Id)); + // Assert.That(run.FailedAt, Is.Null); + // Assert.That(run.IncompleteDetails, Is.Null); + + // messages = client.GetMessages(thread); + // Assert.That(messages.Count, Is.EqualTo(2)); + + // Assert.That(messages.ElementAt(0).Role, Is.EqualTo(MessageRole.Assistant)); + // Assert.That(messages.ElementAt(1).Role, Is.EqualTo(MessageRole.User)); + // Assert.That(messages.ElementAt(1).Id, Is.EqualTo(message.Id)); + //} + + //[Test] + //public void BasicRunStepFunctionalityWorks() + //{ + // AssistantClient client = GetTestClient(); + // Assistant assistant = client.CreateAssistant("gpt-3.5-turbo", new AssistantCreationOptions() + // { + // Tools = { new CodeInterpreterToolDefinition() }, + // Instructions = "Call the code interpreter tool when asked to visualize mathematical concepts.", + // }); + // Validate(assistant); + + // AssistantThread thread = client.CreateThread(new() + // { + // InitialMessages = { new(["Please graph the equation y = 3x + 4"]), }, + // }); + // Validate(thread); + + // ThreadRun run = client.CreateRun(thread, assistant); + // Validate(run); + + // while (!run.Status.IsTerminal) + // { + // Thread.Sleep(1000); + // run = client.GetRun(run); + // } + // Assert.That(run.Status, Is.EqualTo(RunStatus.Completed)); + // Assert.That(run.Usage?.TotalTokens, Is.GreaterThan(0)); + + // ClientPageable runSteps = client.GetRunSteps(run); + // Assert.That(runSteps.Count, Is.GreaterThan(1)); + // Assert.Multiple(() => + // { + // Assert.That(runSteps.First().AssistantId, Is.EqualTo(assistant.Id)); + // Assert.That(runSteps.First().ThreadId, Is.EqualTo(thread.Id)); + // Assert.That(runSteps.First().RunId, Is.EqualTo(run.Id)); + // Assert.That(runSteps.First().CreatedAt, Is.GreaterThan(s_2024)); + // Assert.That(runSteps.First().CompletedAt, Is.GreaterThan(s_2024)); + // }); + // RunStepDetails details = runSteps.First().Details; + // Assert.That(details?.CreatedMessageId, Is.Not.Null.And.Not.Empty); + + // details = runSteps.ElementAt(1).Details; + // Assert.Multiple(() => + // { + // Assert.That(details?.ToolCalls.Count, Is.GreaterThan(0)); + // Assert.That(details.ToolCalls[0].ToolKind, Is.EqualTo(RunStepToolCallKind.CodeInterpreter)); + // Assert.That(details.ToolCalls[0].ToolCallId, Is.Not.Null.And.Not.Empty); + // Assert.That(details.ToolCalls[0].CodeInterpreterInput, Is.Not.Null.And.Not.Empty); + // Assert.That(details.ToolCalls[0].CodeInterpreterOutputs?.Count, Is.GreaterThan(0)); + // Assert.That(details.ToolCalls[0].CodeInterpreterOutputs[0].ImageFileId, Is.Not.Null.And.Not.Empty); + // }); + //} + + //[Test] + //public void SettingResponseFormatWorks() + //{ + // AssistantClient client = GetTestClient(); + // Assistant assistant = client.CreateAssistant("gpt-4-turbo", new() + // { + // ResponseFormat = AssistantResponseFormat.JsonObject, + // }); + // Validate(assistant); + // Assert.That(assistant.ResponseFormat, Is.EqualTo(AssistantResponseFormat.JsonObject)); + // assistant = client.ModifyAssistant(assistant, new() + // { + // ResponseFormat = AssistantResponseFormat.Text, + // }); + // Assert.That(assistant.ResponseFormat, Is.EqualTo(AssistantResponseFormat.Text)); + // AssistantThread thread = client.CreateThread(); + // Validate(thread); + // ThreadMessage message = client.CreateMessage(thread, ["Write some JSON for me!"]); + // Validate(message); + // ThreadRun run = client.CreateRun(thread, assistant, new() + // { + // ResponseFormat = AssistantResponseFormat.JsonObject, + // }); + // Validate(run); + // Assert.That(run.ResponseFormat, Is.EqualTo(AssistantResponseFormat.JsonObject)); + //} + + //[Test] + //public void FunctionToolsWork() + //{ + // AssistantClient client = GetTestClient(); + // Assistant assistant = client.CreateAssistant("gpt-3.5-turbo", new AssistantCreationOptions() + // { + // Tools = + // { + // new FunctionToolDefinition() + // { + // FunctionName = "get_favorite_food_for_day_of_week", + // Description = "gets the user's favorite food for a given day of the week, like Tuesday", + // Parameters = BinaryData.FromObjectAsJson(new + // { + // type = "object", + // properties = new + // { + // day_of_week = new + // { + // type = "string", + // description = "a day of the week, like Tuesday or Saturday", + // } + // } + // }), + // }, + // }, + // }); + // Validate(assistant); + // Assert.That(assistant.Tools?.Count, Is.EqualTo(1)); + + // FunctionToolDefinition responseToolDefinition = assistant.Tools[0] as FunctionToolDefinition; + // Assert.That(responseToolDefinition?.FunctionName, Is.EqualTo("get_favorite_food_for_day_of_week")); + // Assert.That(responseToolDefinition?.Parameters, Is.Not.Null); + + // ThreadRun run = client.CreateThreadAndRun( + // assistant, + // new ThreadCreationOptions() + // { + // InitialMessages = { new(["What should I eat on Thursday?"]) }, + // }, + // new RunCreationOptions() + // { + // AdditionalInstructions = "Call provided tools when appropriate.", + // }); + // Validate(run); + + // for (int i = 0; i < 10 && !run.Status.IsTerminal; i++) + // { + // Thread.Sleep(500); + // run = client.GetRun(run); + // } + // Assert.That(run.Status, Is.EqualTo(RunStatus.RequiresAction)); + // Assert.That(run.RequiredActions?.Count, Is.EqualTo(1)); + // Assert.That(run.RequiredActions[0].ToolCallId, Is.Not.Null.And.Not.Empty); + // Assert.That(run.RequiredActions[0].FunctionName, Is.EqualTo("get_favorite_food_for_day_of_week")); + // Assert.That(run.RequiredActions[0].FunctionArguments, Is.Not.Null.And.Not.Empty); + + // run = client.SubmitToolOutputsToRun(run, [new(run.RequiredActions[0].ToolCallId, "tacos")]); + // Assert.That(run.Status.IsTerminal, Is.False); + + // for (int i = 0; i < 10 && !run.Status.IsTerminal; i++) + // { + // Thread.Sleep(500); + // run = client.GetRun(run); + // } + // Assert.That(run.Status, Is.EqualTo(RunStatus.Completed)); + + // ClientPageable messages = client.GetMessages(run.ThreadId, itemOrder: 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); + // Assert.That(messages.First().Content[0].Text, Does.Contain("tacos")); + //} + + //[Test] + //public async Task StreamingRunWorks() + //{ + // AssistantClient client = new(); + // Assistant assistant = await client.CreateAssistantAsync("gpt-3.5-turbo"); + // Validate(assistant); + + // AssistantThread thread = await client.CreateThreadAsync(new() + // { + // InitialMessages = { new(["Hello there, assistant! How are you today?"]), }, + // }); + // Validate(thread); + + // Stopwatch stopwatch = Stopwatch.StartNew(); + // void Print(string message) => Console.WriteLine($"[{stopwatch.ElapsedMilliseconds,6}] {message}"); + + // AsyncCollectionResult streamingResult + // = client.CreateRunStreamingAsync(thread.Id, assistant.Id); + + // Print(">>> Connected <<<"); + + // await foreach (StreamingUpdate update in streamingResult) + // { + // string message = $"{update.UpdateKind} "; + // if (update is RunUpdate runUpdate) + // { + // message += $"at {update.UpdateKind switch + // { + // StreamingUpdateReason.RunCreated => runUpdate.Value.CreatedAt, + // StreamingUpdateReason.RunQueued => runUpdate.Value.StartedAt, + // StreamingUpdateReason.RunInProgress => runUpdate.Value.StartedAt, + // StreamingUpdateReason.RunCompleted => runUpdate.Value.CompletedAt, + // _ => "???", + // }}"; + // } + // if (update is MessageContentUpdate contentUpdate) + // { + // if (contentUpdate.Role.HasValue) + // { + // message += $"[{contentUpdate.Role}]"; + // } + // message += $"[{contentUpdate.MessageIndex}] {contentUpdate.Text}"; + // } + // Print(message); + // } + // Print(">>> Done <<<"); + //} + + //[TestCase] + //public async Task StreamingToolCall() + //{ + // AssistantClient client = GetTestClient(); + // FunctionToolDefinition getWeatherTool = new("get_current_weather", "Gets the user's current weather"); + // Assistant assistant = await client.CreateAssistantAsync("gpt-3.5-turbo", new() + // { + // Tools = { getWeatherTool } + // }); + // Validate(assistant); + + // Stopwatch stopwatch = Stopwatch.StartNew(); + // void Print(string message) => Console.WriteLine($"[{stopwatch.ElapsedMilliseconds,6}] {message}"); + + // Print(" >>> Beginning call ... "); + // AsyncCollectionResult asyncResults = client.CreateThreadAndRunStreamingAsync( + // assistant, + // new() + // { + // InitialMessages = { new(["What should I wear outside right now?"]), }, + // }); + // Print(" >>> Starting enumeration ..."); + + // ThreadRun run = null; + + // do + // { + // run = null; + // List toolOutputs = []; + // await foreach (StreamingUpdate update in asyncResults) + // { + // string message = update.UpdateKind.ToString(); + + // if (update is RunUpdate runUpdate) + // { + // message += $" run_id:{runUpdate.Value.Id}"; + // run = runUpdate.Value; + // } + // if (update is RequiredActionUpdate requiredActionUpdate) + // { + // Assert.That(requiredActionUpdate.FunctionName, Is.EqualTo(getWeatherTool.FunctionName)); + // Assert.That(requiredActionUpdate.GetThreadRun().Status, Is.EqualTo(RunStatus.RequiresAction)); + // message += $" {requiredActionUpdate.FunctionName}"; + // toolOutputs.Add(new(requiredActionUpdate.ToolCallId, "warm and sunny")); + // } + // if (update is MessageContentUpdate contentUpdate) + // { + // message += $" {contentUpdate.Text}"; + // } + // Print(message); + // } + // if (toolOutputs.Count > 0) + // { + // asyncResults = client.SubmitToolOutputsToRunStreamingAsync(run, toolOutputs); + // } + // } while (run?.Status.IsTerminal == false); + //} + + //[Test] + //public void BasicFileSearchWorks() + //{ + // // First, we need to upload a simple test file. + // FileClient fileClient = new(); + // OpenAIFileInfo testFile = fileClient.UploadFile( + // BinaryData.FromString(""" + // This file describes the favorite foods of several people. + + // Summanus Ferdinand: tacos + // Tekakwitha Effie: pizza + // Filip Carola: cake + // """).ToStream(), + // "favorite_foods.txt", + // FileUploadPurpose.Assistants); + // Validate(testFile); + + // AssistantClient client = GetTestClient(); + + // // Create an assistant, using the creation helper to make a new vector store + // Assistant assistant = client.CreateAssistant("gpt-4-turbo", new() + // { + // Tools = { new FileSearchToolDefinition() }, + // ToolResources = new() + // { + // FileSearch = new() + // { + // NewVectorStores = + // { + // new VectorStoreCreationHelper([testFile.Id]), + // } + // } + // } + // }); + // Validate(assistant); + // Assert.That(assistant.ToolResources?.FileSearch?.VectorStoreIds, Has.Count.EqualTo(1)); + // string createdVectorStoreId = assistant.ToolResources.FileSearch.VectorStoreIds[0]; + // _vectorStoreIdsToDelete.Add(createdVectorStoreId); + + // // Modify an assistant to use the existing vector store + // assistant = client.ModifyAssistant(assistant, new AssistantModificationOptions() + // { + // ToolResources = new() + // { + // FileSearch = new() + // { + // VectorStoreIds = { assistant.ToolResources.FileSearch.VectorStoreIds[0] }, + // }, + // }, + // }); + // Assert.That(assistant.ToolResources?.FileSearch?.VectorStoreIds, Has.Count.EqualTo(1)); + // Assert.That(assistant.ToolResources.FileSearch.VectorStoreIds[0], Is.EqualTo(createdVectorStoreId)); + + // // Create a thread with an override vector store + // AssistantThread thread = client.CreateThread(new ThreadCreationOptions() + // { + // InitialMessages = { new(["Using the files you have available, what's Filip's favorite food?"]) }, + // ToolResources = new() + // { + // FileSearch = new() + // { + // NewVectorStores = + // { + // new VectorStoreCreationHelper([testFile.Id]) + // } + // } + // } + // }); + // Validate(thread); + // Assert.That(thread.ToolResources?.FileSearch?.VectorStoreIds, Has.Count.EqualTo(1)); + // createdVectorStoreId = thread.ToolResources.FileSearch.VectorStoreIds[0]; + // _vectorStoreIdsToDelete.Add(createdVectorStoreId); + + // // Ensure that modifying the thread with an existing vector store works + // thread = client.ModifyThread(thread, new ThreadModificationOptions() + // { + // ToolResources = new() + // { + // FileSearch = new() + // { + // VectorStoreIds = { createdVectorStoreId }, + // } + // } + // }); + // Assert.That(thread.ToolResources?.FileSearch?.VectorStoreIds, Has.Count.EqualTo(1)); + // Assert.That(thread.ToolResources.FileSearch.VectorStoreIds[0], Is.EqualTo(createdVectorStoreId)); + + // ThreadRun run = client.CreateRun(thread, assistant); + // Validate(run); + // do + // { + // Thread.Sleep(1000); + // run = client.GetRun(run); + // } while (run?.Status.IsTerminal == false); + // Assert.That(run.Status, Is.EqualTo(RunStatus.Completed)); + + // ClientPageable messages = client.GetMessages(thread, itemOrder: ListOrder.NewestFirst); + // foreach (ThreadMessage message in messages) + // { + // foreach (MessageContent content in message.Content) + // { + // Console.WriteLine(content.Text); + // foreach (TextAnnotation annotation in content.TextAnnotations) + // { + // Console.WriteLine($" --> From file: {annotation.InputFileId}, quote: {annotation.InputQuote}, replacement: {annotation.TextToReplace}"); + // } + // } + // } + // Assert.That(messages.Count() > 1); + // Assert.That(messages.Any(message => message.Content.Any(content => content.Text.ToLower().Contains("cake")))); + //} [Test] - public async Task StreamingRunWorks() - { - AssistantClient client = new(); - Assistant assistant = await client.CreateAssistantAsync("gpt-3.5-turbo"); - Validate(assistant); - - AssistantThread thread = await client.CreateThreadAsync(new() - { - InitialMessages = { new(["Hello there, assistant! How are you today?"]), }, - }); - Validate(thread); - - Stopwatch stopwatch = Stopwatch.StartNew(); - void Print(string message) => Console.WriteLine($"[{stopwatch.ElapsedMilliseconds,6}] {message}"); - - AsyncResultCollection streamingResult - = client.CreateRunStreamingAsync(thread.Id, assistant.Id); - - Print(">>> Connected <<<"); - - await foreach (StreamingUpdate update in streamingResult) - { - string message = $"{update.UpdateKind} "; - if (update is RunUpdate runUpdate) - { - message += $"at {update.UpdateKind switch - { - StreamingUpdateReason.RunCreated => runUpdate.Value.CreatedAt, - StreamingUpdateReason.RunQueued => runUpdate.Value.StartedAt, - StreamingUpdateReason.RunInProgress => runUpdate.Value.StartedAt, - StreamingUpdateReason.RunCompleted => runUpdate.Value.CompletedAt, - _ => "???", - }}"; - } - if (update is MessageContentUpdate contentUpdate) - { - if (contentUpdate.Role.HasValue) - { - message += $"[{contentUpdate.Role}]"; - } - message += $"[{contentUpdate.MessageIndex}] {contentUpdate.Text}"; - } - Print(message); - } - Print(">>> Done <<<"); - } - - [TestCase] - public async Task StreamingToolCall() + public void CanEnumerateAssistants() { AssistantClient client = GetTestClient(); - FunctionToolDefinition getWeatherTool = new("get_current_weather", "Gets the user's current weather"); - Assistant assistant = await client.CreateAssistantAsync("gpt-3.5-turbo", new() - { - Tools = { getWeatherTool } - }); - Validate(assistant); - - Stopwatch stopwatch = Stopwatch.StartNew(); - void Print(string message) => Console.WriteLine($"[{stopwatch.ElapsedMilliseconds,6}] {message}"); - - Print(" >>> Beginning call ... "); - AsyncResultCollection asyncResults = client.CreateThreadAndRunStreamingAsync( - assistant, - new() - { - InitialMessages = { new(["What should I wear outside right now?"]), }, - }); - Print(" >>> Starting enumeration ..."); - - ThreadRun run = null; - - do - { - run = null; - List toolOutputs = []; - await foreach (StreamingUpdate update in asyncResults) - { - string message = update.UpdateKind.ToString(); - - if (update is RunUpdate runUpdate) - { - message += $" run_id:{runUpdate.Value.Id}"; - run = runUpdate.Value; - } - if (update is RequiredActionUpdate requiredActionUpdate) - { - Assert.That(requiredActionUpdate.FunctionName, Is.EqualTo(getWeatherTool.FunctionName)); - Assert.That(requiredActionUpdate.GetThreadRun().Status, Is.EqualTo(RunStatus.RequiresAction)); - message += $" {requiredActionUpdate.FunctionName}"; - toolOutputs.Add(new(requiredActionUpdate.ToolCallId, "warm and sunny")); - } - if (update is MessageContentUpdate contentUpdate) - { - message += $" {contentUpdate.Text}"; - } - Print(message); - } - if (toolOutputs.Count > 0) - { - asyncResults = client.SubmitToolOutputsToRunStreamingAsync(run, toolOutputs); - } - } while (run?.Status.IsTerminal == false); - } - - [Test] - public void BasicFileSearchWorks() - { - // First, we need to upload a simple test file. - FileClient fileClient = new(); - OpenAIFileInfo testFile = fileClient.UploadFile( - BinaryData.FromString(""" - This file describes the favorite foods of several people. - - Summanus Ferdinand: tacos - Tekakwitha Effie: pizza - Filip Carola: cake - """).ToStream(), - "favorite_foods.txt", - FileUploadPurpose.Assistants); - Validate(testFile); - AssistantClient client = GetTestClient(); - - // Create an assistant, using the creation helper to make a new vector store - Assistant assistant = client.CreateAssistant("gpt-4-turbo", new() - { - Tools = { new FileSearchToolDefinition() }, - ToolResources = new() - { - FileSearch = new() - { - NewVectorStores = - { - new VectorStoreCreationHelper([testFile.Id]), - } - } - } - }); - Validate(assistant); - Assert.That(assistant.ToolResources?.FileSearch?.VectorStoreIds, Has.Count.EqualTo(1)); - string createdVectorStoreId = assistant.ToolResources.FileSearch.VectorStoreIds[0]; - _vectorStoreIdsToDelete.Add(createdVectorStoreId); - - // Modify an assistant to use the existing vector store - assistant = client.ModifyAssistant(assistant, new AssistantModificationOptions() - { - ToolResources = new() - { - FileSearch = new() - { - VectorStoreIds = { assistant.ToolResources.FileSearch.VectorStoreIds[0] }, - }, - }, - }); - Assert.That(assistant.ToolResources?.FileSearch?.VectorStoreIds, Has.Count.EqualTo(1)); - Assert.That(assistant.ToolResources.FileSearch.VectorStoreIds[0], Is.EqualTo(createdVectorStoreId)); - - // Create a thread with an override vector store - AssistantThread thread = client.CreateThread(new ThreadCreationOptions() - { - InitialMessages = { new(["Using the files you have available, what's Filip's favorite food?"]) }, - ToolResources = new() - { - FileSearch = new() - { - NewVectorStores = - { - new VectorStoreCreationHelper([testFile.Id]) - } - } - } - }); - Validate(thread); - Assert.That(thread.ToolResources?.FileSearch?.VectorStoreIds, Has.Count.EqualTo(1)); - createdVectorStoreId = thread.ToolResources.FileSearch.VectorStoreIds[0]; - _vectorStoreIdsToDelete.Add(createdVectorStoreId); - - // Ensure that modifying the thread with an existing vector store works - thread = client.ModifyThread(thread, new ThreadModificationOptions() - { - ToolResources = new() - { - FileSearch = new() - { - VectorStoreIds = { createdVectorStoreId }, - } - } - }); - Assert.That(thread.ToolResources?.FileSearch?.VectorStoreIds, Has.Count.EqualTo(1)); - Assert.That(thread.ToolResources.FileSearch.VectorStoreIds[0], Is.EqualTo(createdVectorStoreId)); - - ThreadRun run = client.CreateRun(thread, assistant); - Validate(run); - do - { - Thread.Sleep(1000); - run = client.GetRun(run); - } while (run?.Status.IsTerminal == false); - Assert.That(run.Status, Is.EqualTo(RunStatus.Completed)); - - PageableCollection messages = client.GetMessages(thread, resultOrder: ListOrder.NewestFirst); - foreach (ThreadMessage message in messages) - { - foreach (MessageContent content in message.Content) - { - Console.WriteLine(content.Text); - foreach (TextAnnotation annotation in content.TextAnnotations) - { - Console.WriteLine($" --> From file: {annotation.InputFileId}, quote: {annotation.InputQuote}, replacement: {annotation.TextToReplace}"); - } - } - } - Assert.That(messages.Count() > 1); - Assert.That(messages.Any(message => message.Content.Any(content => content.Text.ToLower().Contains("cake")))); - } - - [Test] - public async Task CanEnumerateAssistants() - { - 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}")); - } + //// 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}")); + //} // Page through collection int count = 0; - AsyncPageableCollection assistants = client.GetAssistantsAsync(ListOrder.NewestFirst); - - int lastIdSeen = int.MaxValue; + IEnumerable assistants = client.GetAssistants(ListOrder.NewestFirst, pageSize: 2); - await foreach (Assistant assistant in assistants) + foreach (Assistant assistant in assistants) { - 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++; - if (lastIdSeen == 0 || count > 100) - { - break; - } } Assert.That(count, Is.GreaterThanOrEqualTo(10)); } - [Test] - public async Task CanPageThroughAssistantCollection() - { - 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}")); - } - - // Page through collection - int count = 0; - int pageCount = 0; - AsyncPageableCollection assistants = client.GetAssistantsAsync(ListOrder.NewestFirst); - IAsyncEnumerable> pages = assistants.AsPages(pageSizeHint: 2); - - int lastIdSeen = int.MaxValue; - - await foreach (ResultPage page in pages) - { - foreach (Assistant assistant in page) - { - 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++; - } - - pageCount++; - if (lastIdSeen == 0 || count > 100) - { - break; - } - } - - Assert.That(count, Is.GreaterThanOrEqualTo(10)); - Assert.That(pageCount, Is.GreaterThanOrEqualTo(5)); - } + //[Test] + //public async Task CanEnumerateAssistantsByPage() + //{ + // 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 a count of the assistants as a baseline. + // IEnumerable enumerable = client.GetAssistants(ListOrder.NewestFirst, pageSize: 100); + // int totalCount = enumerable.Count(); + + // // Page through collection + // int itemCount = 0; + // int pageCount = 0; + // IAs assistants = client.GetAssistantsAsync(pageSize: 2, itemOrder: ListOrder.NewestFirst); + // IAsyncEnumerable> pages = assistants.AsPages(); + + // await foreach (ClientPage 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 enable + +// [Test] +// public async Task CanEnumerateAssistantsByPageAndResume() +// { +// 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 a count of the assistants as a baseline. +// ClientPageable enumerable = client.GetAssistants(ListOrder.NewestFirst, pageSize: 100); +// int totalCount = enumerable.Count(); + +// // Page through collection +// int itemCount = 0; +// int pageCount = 0; +// AsyncClientPageable assistants = client.GetAssistantsAsync(pageSize: 2, itemOrder: ListOrder.NewestFirst); +// IAsyncEnumerable> pages = assistants.AsPages(); + +// string? pageToken = default; + +// // First iteration - stop after two pages +// await foreach (ClientPage page in pages) +// { +// foreach (Assistant assistant in page.Values) +// { +// itemCount++; +// } + +// pageCount++; + +// if (pageCount > 1) +// { +// pageToken = page.NextPageToken; +// break; +// } +// } + +// // 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, itemOrder: 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 (ClientPage 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. + // //ClientPageable 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. + // ClientPageable assistants = client.GetAssistants( + // ListOrder.OldestFirst, + // pageSize: 2); + + // IEnumerable> pages = assistants.AsPages(); + + // // Get first page + // ClientPage firstPage = default; + // ClientPage secondPage = default; + // ClientPage 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); + // ClientPage 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); + // ClientPage 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. + // //ClientPageable 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. + // ClientPageable assistants = client.GetAssistants( + // ListOrder.OldestFirst, + // pageSize: 2); + + // IEnumerable> pages = assistants.AsPages(); + + // // Get first page + // ClientPage firstPage = default; + // foreach (var page in pages) + // { + // firstPage = page; + // break; + // } + + // // Get second page + // pages = assistants.AsPages(firstPage.NextPageToken); + // ClientPage secondPage = default; + // foreach (var page in pages) + // { + // secondPage = page; + // break; + // } + + // // Get third page + // pages = assistants.AsPages(secondPage.NextPageToken); + // ClientPage 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); + // ClientPage 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); + // ClientPage 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] protected void Cleanup() diff --git a/.dotnet/tests/TestScenarios/Assistants/VectorStoreTests.cs b/.dotnet/tests/TestScenarios/Assistants/VectorStoreTests.cs index bd4e4f646..7225ff55b 100644 --- a/.dotnet/tests/TestScenarios/Assistants/VectorStoreTests.cs +++ b/.dotnet/tests/TestScenarios/Assistants/VectorStoreTests.cs @@ -18,317 +18,317 @@ namespace OpenAI.Tests.VectorStores; #pragma warning disable OPENAI001 public partial class VectorStoreTests { - [Test] - public void CanCreateGetAndDeleteVectorStores() - { - VectorStoreClient client = GetTestClient(); - - VectorStore vectorStore = client.CreateVectorStore(); - Validate(vectorStore); - bool deleted = client.DeleteVectorStore(vectorStore); - Assert.That(deleted, Is.True); - _vectorStoresToDelete.RemoveAt(_vectorStoresToDelete.Count - 1); - - IReadOnlyList testFiles = GetNewTestFiles(5); - - vectorStore = client.CreateVectorStore(new() - { - FileIds = { testFiles[0].Id }, - Name = "test vector store", - ExpirationPolicy = new VectorStoreExpirationPolicy() - { - Anchor = VectorStoreExpirationAnchor.LastActiveAt, - Days = 3, - }, - Metadata = - { - ["test-key"] = "test-value", - }, - }); - Validate(vectorStore); - 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"); - }); - vectorStore = client.GetVectorStore(vectorStore); - 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.Metadata?.TryGetValue("test-key", out string metadataValue) == true && metadataValue == "test-value"); - }); - - deleted = client.DeleteVectorStore(vectorStore.Id); - Assert.That(deleted, Is.True); - _vectorStoresToDelete.RemoveAt(_vectorStoresToDelete.Count - 1); - - vectorStore = client.CreateVectorStore(new() - { - FileIds = testFiles.Select(file => file.Id).ToList() - }); - Validate(vectorStore); - Assert.Multiple(() => - { - Assert.That(vectorStore.Name, Is.Null.Or.Empty); - Assert.That(vectorStore.FileCounts.Total, Is.EqualTo(5)); - }); - } - - [Test] - public void CanEnumerateVectorStores() - { - VectorStoreClient client = GetTestClient(); - for (int i = 0; i < 10; i++) - { - VectorStore vectorStore = client.CreateVectorStore(new VectorStoreCreationOptions() - { - Name = $"Test Vector Store {i}", - }); - Validate(vectorStore); - Assert.That(vectorStore.Name, Is.EqualTo($"Test Vector Store {i}")); - } - - int lastIdSeen = int.MaxValue; - int count = 0; - - foreach (VectorStore vectorStore in client.GetVectorStores(ListOrder.NewestFirst)) - { - Assert.That(vectorStore.Id, Is.Not.Null); - if (vectorStore.Name?.StartsWith("Test Vector Store ") == true) - { - string idString = vectorStore.Name["Test Vector Store ".Length..]; - - Assert.That(int.TryParse(idString, out int seenId), Is.True); - Assert.That(seenId, Is.LessThan(lastIdSeen)); - lastIdSeen = seenId; - } - if (lastIdSeen == 0 || ++count >= 100) - { - break; - } - } - - Assert.That(lastIdSeen, Is.EqualTo(0)); - } - - [Test] - 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}", - }); - Validate(vectorStore); - Assert.That(vectorStore.Name, Is.EqualTo($"Test Vector Store {i}")); - } - - int lastIdSeen = int.MaxValue; - int count = 0; - - await foreach (VectorStore vectorStore in client.GetVectorStoresAsync(ListOrder.NewestFirst)) - { - Assert.That(vectorStore.Id, Is.Not.Null); - if (vectorStore.Name?.StartsWith("Test Vector Store ") == true) - { - string idString = vectorStore.Name["Test Vector Store ".Length..]; - - Assert.That(int.TryParse(idString, out int seenId), Is.True); - Assert.That(seenId, Is.LessThan(lastIdSeen)); - lastIdSeen = seenId; - } - if (lastIdSeen == 0 || ++count >= 100) - { - break; - } - } - - Assert.That(lastIdSeen, Is.EqualTo(0)); - } - - [Test] - public void CanAssociateFiles() - { - VectorStoreClient client = GetTestClient(); - VectorStore vectorStore = client.CreateVectorStore(); - Validate(vectorStore); - - IReadOnlyList files = GetNewTestFiles(3); - - foreach (OpenAIFileInfo file in files) - { - VectorStoreFileAssociation association = client.AddFileToVectorStore(vectorStore, file); - Validate(association); - Assert.Multiple(() => - { - Assert.That(association.FileId, Is.EqualTo(file.Id)); - Assert.That(association.VectorStoreId, Is.EqualTo(vectorStore.Id)); - Assert.That(association.LastError, Is.Null); - Assert.That(association.CreatedAt, Is.GreaterThan(s_2024)); - Assert.That(association.Status, Is.EqualTo(VectorStoreFileAssociationStatus.InProgress)); - }); - } - - bool removed = client.RemoveFileFromStore(vectorStore, files[0]); - Assert.True(removed); - _associationsToRemove.RemoveAt(0); - - // Errata: removals aren't immediately reflected when requesting the list - Thread.Sleep(1000); - - int count = 0; - foreach (VectorStoreFileAssociation association in client.GetFileAssociations(vectorStore)) - { - count++; - Assert.That(association.FileId, Is.Not.EqualTo(files[0].Id)); - Assert.That(association.VectorStoreId, Is.EqualTo(vectorStore.Id)); - } - Assert.That(count, Is.EqualTo(2)); - } - - [Test] - public void CanUseBatchIngestion() - { - VectorStoreClient client = GetTestClient(); - VectorStore vectorStore = client.CreateVectorStore(); - Validate(vectorStore); - - IReadOnlyList testFiles = GetNewTestFiles(5); - - VectorStoreBatchFileJob batchJob = client.CreateBatchFileJob(vectorStore, testFiles); - Validate(batchJob); - - 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)); - }); - - for (int i = 0; i < 10 && client.GetBatchFileJob(batchJob).Value.Status != VectorStoreBatchFileJobStatus.Completed; i++) - { - Thread.Sleep(500); - } - - foreach (VectorStoreFileAssociation association in client.GetFileAssociations(batchJob)) - { - Assert.Multiple(() => - { - Assert.That(association.FileId, Is.Not.Null); - Assert.That(association.VectorStoreId, Is.EqualTo(vectorStore.Id)); - Assert.That(association.Status, Is.EqualTo(VectorStoreFileAssociationStatus.Completed)); - // Assert.That(association.Size, Is.GreaterThan(0)); - Assert.That(association.CreatedAt, Is.GreaterThan(s_2024)); - Assert.That(association.LastError, Is.Null); - }); - } - } - - private IReadOnlyList GetNewTestFiles(int count) - { - List files = []; - - FileClient client = new(); - for (int i = 0; i < count; i++) - { - OpenAIFileInfo file = client.UploadFile( - BinaryData.FromString("This is a test file").ToStream(), - $"test_file_{i.ToString().PadLeft(3, '0')}.txt", - FileUploadPurpose.Assistants); - Validate(file); - files.Add(file); - } - - return files; - } - [TearDown] - protected void Cleanup() - { - FileClient fileClient = new(); - VectorStoreClient vectorStoreClient = new(); - RequestOptions requestOptions = new() - { - ErrorOptions = ClientErrorBehaviors.NoThrow, - }; - foreach (VectorStoreBatchFileJob job in _jobsToCancel) - { - ClientResult protocolResult = vectorStoreClient.CancelBatchFileJob(job.VectorStoreId, job.BatchId, requestOptions); - Console.WriteLine($"Cleanup: {job.BatchId} => {protocolResult?.GetRawResponse()?.Status}"); - } - foreach (VectorStoreFileAssociation association in _associationsToRemove) - { - ClientResult protocolResult = vectorStoreClient.RemoveFileFromStore(association.VectorStoreId, association.FileId, requestOptions); - Console.WriteLine($"Cleanup: {association.FileId}<->{association.VectorStoreId} => {protocolResult?.GetRawResponse()?.Status}"); - } - foreach (OpenAIFileInfo file in _filesToDelete) - { - Console.WriteLine($"Cleanup: {file.Id} -> {fileClient.DeleteFile(file.Id, requestOptions)?.GetRawResponse()?.Status}"); - } - foreach (VectorStore vectorStore in _vectorStoresToDelete) - { - Console.WriteLine($"Cleanup: {vectorStore.Id} => {vectorStoreClient.DeleteVectorStore(vectorStore.Id, requestOptions)?.GetRawResponse()?.Status}"); - } - _filesToDelete.Clear(); - _vectorStoresToDelete.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 VectorStoreBatchFileJob job) - { - Assert.That(job.BatchId, Is.Not.Null); - _jobsToCancel.Add(job); - } - else if (target is VectorStoreFileAssociation association) - { - Assert.That(association?.FileId, Is.Not.Null); - Assert.That(association?.VectorStoreId, Is.Not.Null); - _associationsToRemove.Add(association); - } - else if (target is OpenAIFileInfo file) - { - Assert.That(file?.Id, Is.Not.Null); - _filesToDelete.Add(file); - } - else if (target is VectorStore vectorStore) - { - Assert.That(vectorStore?.Id, Is.Not.Null); - _vectorStoresToDelete.Add(vectorStore); - } - else - { - throw new NotImplementedException($"{nameof(Validate)} helper not implemented for: {typeof(T)}"); - } - } - - private readonly List _jobsToCancel = []; - private readonly List _associationsToRemove = []; - private readonly List _filesToDelete = []; - private readonly List _vectorStoresToDelete = []; - - private static VectorStoreClient GetTestClient() => GetTestClient(TestScenario.VectorStores); - - private static readonly DateTimeOffset s_2024 = new(2024, 1, 1, 0, 0, 0, TimeSpan.Zero); + //[Test] + //public void CanCreateGetAndDeleteVectorStores() + //{ + // VectorStoreClient client = GetTestClient(); + + // VectorStore vectorStore = client.CreateVectorStore(); + // Validate(vectorStore); + // bool deleted = client.DeleteVectorStore(vectorStore); + // Assert.That(deleted, Is.True); + // _vectorStoresToDelete.RemoveAt(_vectorStoresToDelete.Count - 1); + + // IReadOnlyList testFiles = GetNewTestFiles(5); + + // vectorStore = client.CreateVectorStore(new() + // { + // FileIds = { testFiles[0].Id }, + // Name = "test vector store", + // ExpirationPolicy = new VectorStoreExpirationPolicy() + // { + // Anchor = VectorStoreExpirationAnchor.LastActiveAt, + // Days = 3, + // }, + // Metadata = + // { + // ["test-key"] = "test-value", + // }, + // }); + // Validate(vectorStore); + // 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"); + // }); + // vectorStore = client.GetVectorStore(vectorStore); + // 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.Metadata?.TryGetValue("test-key", out string metadataValue) == true && metadataValue == "test-value"); + // }); + + // deleted = client.DeleteVectorStore(vectorStore.Id); + // Assert.That(deleted, Is.True); + // _vectorStoresToDelete.RemoveAt(_vectorStoresToDelete.Count - 1); + + // vectorStore = client.CreateVectorStore(new() + // { + // FileIds = testFiles.Select(file => file.Id).ToList() + // }); + // Validate(vectorStore); + // Assert.Multiple(() => + // { + // Assert.That(vectorStore.Name, Is.Null.Or.Empty); + // Assert.That(vectorStore.FileCounts.Total, Is.EqualTo(5)); + // }); + //} + + //[Test] + //public void CanEnumerateVectorStores() + //{ + // VectorStoreClient client = GetTestClient(); + // for (int i = 0; i < 10; i++) + // { + // VectorStore vectorStore = client.CreateVectorStore(new VectorStoreCreationOptions() + // { + // Name = $"Test Vector Store {i}", + // }); + // Validate(vectorStore); + // Assert.That(vectorStore.Name, Is.EqualTo($"Test Vector Store {i}")); + // } + + // int lastIdSeen = int.MaxValue; + // int count = 0; + + // foreach (VectorStore vectorStore in client.GetVectorStores(itemOrder: ListOrder.NewestFirst)) + // { + // Assert.That(vectorStore.Id, Is.Not.Null); + // if (vectorStore.Name?.StartsWith("Test Vector Store ") == true) + // { + // string idString = vectorStore.Name["Test Vector Store ".Length..]; + + // Assert.That(int.TryParse(idString, out int seenId), Is.True); + // Assert.That(seenId, Is.LessThan(lastIdSeen)); + // lastIdSeen = seenId; + // } + // if (lastIdSeen == 0 || ++count >= 100) + // { + // break; + // } + // } + + // Assert.That(lastIdSeen, Is.EqualTo(0)); + //} + + //[Test] + //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}", + // }); + // Validate(vectorStore); + // Assert.That(vectorStore.Name, Is.EqualTo($"Test Vector Store {i}")); + // } + + // int lastIdSeen = int.MaxValue; + // int count = 0; + + // await foreach (VectorStore vectorStore in client.GetVectorStoresAsync(itemOrder: ListOrder.NewestFirst)) + // { + // Assert.That(vectorStore.Id, Is.Not.Null); + // if (vectorStore.Name?.StartsWith("Test Vector Store ") == true) + // { + // string idString = vectorStore.Name["Test Vector Store ".Length..]; + + // Assert.That(int.TryParse(idString, out int seenId), Is.True); + // Assert.That(seenId, Is.LessThan(lastIdSeen)); + // lastIdSeen = seenId; + // } + // if (lastIdSeen == 0 || ++count >= 100) + // { + // break; + // } + // } + + // Assert.That(lastIdSeen, Is.EqualTo(0)); + //} + + //[Test] + //public void CanAssociateFiles() + //{ + // VectorStoreClient client = GetTestClient(); + // VectorStore vectorStore = client.CreateVectorStore(); + // Validate(vectorStore); + + // IReadOnlyList files = GetNewTestFiles(3); + + // foreach (OpenAIFileInfo file in files) + // { + // VectorStoreFileAssociation association = client.AddFileToVectorStore(vectorStore, file); + // Validate(association); + // Assert.Multiple(() => + // { + // Assert.That(association.FileId, Is.EqualTo(file.Id)); + // Assert.That(association.VectorStoreId, Is.EqualTo(vectorStore.Id)); + // Assert.That(association.LastError, Is.Null); + // Assert.That(association.CreatedAt, Is.GreaterThan(s_2024)); + // Assert.That(association.Status, Is.EqualTo(VectorStoreFileAssociationStatus.InProgress)); + // }); + // } + + // bool removed = client.RemoveFileFromStore(vectorStore, files[0]); + // Assert.True(removed); + // _associationsToRemove.RemoveAt(0); + + // // Errata: removals aren't immediately reflected when requesting the list + // Thread.Sleep(1000); + + // int count = 0; + // foreach (VectorStoreFileAssociation association in client.GetFileAssociations(vectorStore)) + // { + // count++; + // Assert.That(association.FileId, Is.Not.EqualTo(files[0].Id)); + // Assert.That(association.VectorStoreId, Is.EqualTo(vectorStore.Id)); + // } + // Assert.That(count, Is.EqualTo(2)); + //} + + //[Test] + //public void CanUseBatchIngestion() + //{ + // VectorStoreClient client = GetTestClient(); + // VectorStore vectorStore = client.CreateVectorStore(); + // Validate(vectorStore); + + // IReadOnlyList testFiles = GetNewTestFiles(5); + + // VectorStoreBatchFileJob batchJob = client.CreateBatchFileJob(vectorStore, testFiles); + // Validate(batchJob); + + // 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)); + // }); + + // for (int i = 0; i < 10 && client.GetBatchFileJob(batchJob).Value.Status != VectorStoreBatchFileJobStatus.Completed; i++) + // { + // Thread.Sleep(500); + // } + + // foreach (VectorStoreFileAssociation association in client.GetFileAssociations(batchJob)) + // { + // Assert.Multiple(() => + // { + // Assert.That(association.FileId, Is.Not.Null); + // Assert.That(association.VectorStoreId, Is.EqualTo(vectorStore.Id)); + // Assert.That(association.Status, Is.EqualTo(VectorStoreFileAssociationStatus.Completed)); + // // Assert.That(association.Size, Is.GreaterThan(0)); + // Assert.That(association.CreatedAt, Is.GreaterThan(s_2024)); + // Assert.That(association.LastError, Is.Null); + // }); + // } + //} + + //private IReadOnlyList GetNewTestFiles(int count) + //{ + // List files = []; + + // FileClient client = new(); + // for (int i = 0; i < count; i++) + // { + // OpenAIFileInfo file = client.UploadFile( + // BinaryData.FromString("This is a test file").ToStream(), + // $"test_file_{i.ToString().PadLeft(3, '0')}.txt", + // FileUploadPurpose.Assistants); + // Validate(file); + // files.Add(file); + // } + + // return files; + //} + //[TearDown] + //protected void Cleanup() + //{ + // FileClient fileClient = new(); + // VectorStoreClient vectorStoreClient = new(); + // RequestOptions requestOptions = new() + // { + // ErrorOptions = ClientErrorBehaviors.NoThrow, + // }; + // foreach (VectorStoreBatchFileJob job in _jobsToCancel) + // { + // ClientResult protocolResult = vectorStoreClient.CancelBatchFileJob(job.VectorStoreId, job.BatchId, requestOptions); + // Console.WriteLine($"Cleanup: {job.BatchId} => {protocolResult?.GetRawResponse()?.Status}"); + // } + // foreach (VectorStoreFileAssociation association in _associationsToRemove) + // { + // ClientResult protocolResult = vectorStoreClient.RemoveFileFromStore(association.VectorStoreId, association.FileId, requestOptions); + // Console.WriteLine($"Cleanup: {association.FileId}<->{association.VectorStoreId} => {protocolResult?.GetRawResponse()?.Status}"); + // } + // foreach (OpenAIFileInfo file in _filesToDelete) + // { + // Console.WriteLine($"Cleanup: {file.Id} -> {fileClient.DeleteFile(file.Id, requestOptions)?.GetRawResponse()?.Status}"); + // } + // foreach (VectorStore vectorStore in _vectorStoresToDelete) + // { + // Console.WriteLine($"Cleanup: {vectorStore.Id} => {vectorStoreClient.DeleteVectorStore(vectorStore.Id, requestOptions)?.GetRawResponse()?.Status}"); + // } + // _filesToDelete.Clear(); + // _vectorStoresToDelete.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 VectorStoreBatchFileJob job) + // { + // Assert.That(job.BatchId, Is.Not.Null); + // _jobsToCancel.Add(job); + // } + // else if (target is VectorStoreFileAssociation association) + // { + // Assert.That(association?.FileId, Is.Not.Null); + // Assert.That(association?.VectorStoreId, Is.Not.Null); + // _associationsToRemove.Add(association); + // } + // else if (target is OpenAIFileInfo file) + // { + // Assert.That(file?.Id, Is.Not.Null); + // _filesToDelete.Add(file); + // } + // else if (target is VectorStore vectorStore) + // { + // Assert.That(vectorStore?.Id, Is.Not.Null); + // _vectorStoresToDelete.Add(vectorStore); + // } + // else + // { + // throw new NotImplementedException($"{nameof(Validate)} helper not implemented for: {typeof(T)}"); + // } + //} + + //private readonly List _jobsToCancel = []; + //private readonly List _associationsToRemove = []; + //private readonly List _filesToDelete = []; + //private readonly List _vectorStoresToDelete = []; + + //private static VectorStoreClient GetTestClient() => GetTestClient(TestScenario.VectorStores); + + //private static readonly DateTimeOffset s_2024 = new(2024, 1, 1, 0, 0, 0, TimeSpan.Zero); } #pragma warning restore OPENAI001 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) diff --git a/assistants/models.tsp b/assistants/models.tsp index b850a23d1..ff5ccb3ea 100644 --- a/assistants/models.tsp +++ b/assistants/models.tsp @@ -185,10 +185,24 @@ model ListAssistantsResponse { data: AssistantObject[]; first_id: string; + @continuationToken last_id: string; has_more: boolean; } +model ListPublicGistsResponse { + ...GistObject[]; + @Http.header + link:LinkHeader; +} + +model LinkHeader{ + prevLink: url; + nextLink: url; + lastLink: url; + firstLink: url; +} + model DeleteAssistantResponse { id: string; deleted: boolean; @@ -226,6 +240,7 @@ Represents an `assistant` that can call the model and use tools. """) model AssistantObject { /** The identifier, which can be referenced in API endpoints. */ + @continuationToken id: string; @doc(""" diff --git a/assistants/operations.tsp b/assistants/operations.tsp index 3ba885955..2bfd74e1f 100644 --- a/assistants/operations.tsp +++ b/assistants/operations.tsp @@ -41,6 +41,7 @@ interface Assistants { * 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. */ + @continuationToken @query after?: string, /** @@ -51,6 +52,14 @@ interface Assistants { @query before?: string, ): ListAssistantsResponse | ErrorResponse; + @list + @operationId("listPublicGists") + listPublicGists( + @query since?: utcDateTime, + @query per_page?: int32 = 30, + @query page?: int32 = 1, + ): ListPublicGistsResponse | ErrorResponse; + @route("{assistant_id}") @get @operationId("getAssistant")