From c4f7be7845c19ad82477c4fe55937c9668f552bd Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Thu, 17 Jul 2025 14:34:02 -0500 Subject: [PATCH 01/11] GetChatCompletions with generated pagination initial --- .../generator/src/OpenAILibraryGenerator.cs | 1 + ...plicitConversionFromClientResultVisitor.cs | 3 +- .../src/Visitors/PaginationVisitor.cs | 100 ++++++++++++++++++ .../generator/src/Visitors/VisitorHelpers.cs | 14 +++ src/Custom/Chat/ChatClient.Protocol.cs | 2 - src/Custom/Chat/ChatClient.cs | 2 - .../Containers/Internal/GeneratorStubs.cs | 36 ------- src/Custom/Files/Internal/GeneratorStubs.cs | 6 -- src/Custom/Graders/Internal/GeneratorStubs.cs | 12 --- .../Internal/GeneratorStubs.cs | 6 -- src/Generated/ChatClient.cs | 56 ++++++++++ ...GetChatCompletionsAsyncCollectionResult.cs | 67 ++++++++++++ ...ChatCompletionsAsyncCollectionResultOfT.cs | 77 ++++++++++++++ ...lientGetChatCompletionsCollectionResult.cs | 64 +++++++++++ ...ntGetChatCompletionsCollectionResultOfT.cs | 69 ++++++++++++ ...nalListAssistantsResponse.Serialization.cs | 8 ++ ...ernalListMessagesResponse.Serialization.cs | 8 ++ ...ernalListRunStepsResponse.Serialization.cs | 8 ++ .../InternalListRunsResponse.Serialization.cs | 8 ++ .../Batch/InternalBatchJob.Serialization.cs | 8 ++ ...ternalListBatchesResponse.Serialization.cs | 8 ++ ...nternalChatCompletionList.Serialization.cs | 8 ++ ...ChatCompletionMessageList.Serialization.cs | 8 ++ ...ContainerFileListResource.Serialization.cs | 8 ++ ...rnalContainerFileResource.Serialization.cs | 8 ++ ...rnalContainerListResource.Serialization.cs | 8 ++ ...InternalContainerResource.Serialization.cs | 8 ++ ...leteContainerFileResponse.Serialization.cs | 8 ++ ...alDeleteContainerResponse.Serialization.cs | 8 ++ ...nternalDeleteEvalResponse.Serialization.cs | 8 ++ ...rnalDeleteEvalRunResponse.Serialization.cs | 8 ++ .../Evals/InternalEval.Serialization.cs | 8 ++ .../Evals/InternalEvalList.Serialization.cs | 8 ++ .../Evals/InternalEvalRun.Serialization.cs | 8 ++ .../InternalEvalRunList.Serialization.cs | 8 ++ ...InternalEvalRunOutputItem.Serialization.cs | 8 ++ ...rnalEvalRunOutputItemList.Serialization.cs | 8 ++ .../Files/InternalUpload.Serialization.cs | 8 ++ .../Files/InternalUploadPart.Serialization.cs | 8 ++ ...ckpointPermissionResponse.Serialization.cs | 8 ++ .../InternalFineTuningJob.Serialization.cs | 8 ++ ...ckpointPermissionResponse.Serialization.cs | 8 ++ ...ingJobCheckpointsResponse.Serialization.cs | 8 ++ ...neTuningJobEventsResponse.Serialization.cs | 8 ++ ...tedFineTuningJobsResponse.Serialization.cs | 8 ++ ...InternalRunGraderResponse.Serialization.cs | 8 ++ ...nalValidateGraderResponse.Serialization.cs | 8 ++ ...lCreateCompletionResponse.Serialization.cs | 8 ++ ...timeSessionCreateResponse.Serialization.cs | 8 ++ ...tionSessionCreateResponse.Serialization.cs | 8 ++ .../InternalResponseItemList.Serialization.cs | 8 ++ ...tVectorStoreFilesResponse.Serialization.cs | 8 ++ ...lListVectorStoresResponse.Serialization.cs | 8 ++ ...rStoreFileContentResponse.Serialization.cs | 8 ++ ...torStoreSearchResultsPage.Serialization.cs | 8 ++ 55 files changed, 770 insertions(+), 65 deletions(-) create mode 100644 codegen/generator/src/Visitors/PaginationVisitor.cs create mode 100644 src/Generated/ChatClientGetChatCompletionsAsyncCollectionResult.cs create mode 100644 src/Generated/ChatClientGetChatCompletionsAsyncCollectionResultOfT.cs create mode 100644 src/Generated/ChatClientGetChatCompletionsCollectionResult.cs create mode 100644 src/Generated/ChatClientGetChatCompletionsCollectionResultOfT.cs diff --git a/codegen/generator/src/OpenAILibraryGenerator.cs b/codegen/generator/src/OpenAILibraryGenerator.cs index 9915ab0a3..30951a4e2 100644 --- a/codegen/generator/src/OpenAILibraryGenerator.cs +++ b/codegen/generator/src/OpenAILibraryGenerator.cs @@ -38,6 +38,7 @@ protected override void Configure() AddVisitor(new ModelSerializationVisitor()); AddVisitor(new ExperimentalAttributeVisitor()); AddVisitor(new ModelDirectoryVisitor()); + AddVisitor(new PaginationVisitor()); } } } \ No newline at end of file diff --git a/codegen/generator/src/Visitors/ExplicitConversionFromClientResultVisitor.cs b/codegen/generator/src/Visitors/ExplicitConversionFromClientResultVisitor.cs index 84fe172e1..4a5a7d249 100644 --- a/codegen/generator/src/Visitors/ExplicitConversionFromClientResultVisitor.cs +++ b/codegen/generator/src/Visitors/ExplicitConversionFromClientResultVisitor.cs @@ -15,7 +15,8 @@ protected override MethodProvider VisitMethod(MethodProvider method) if (method.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Explicit) && method.Signature.Modifiers.HasFlag(MethodSignatureModifiers.Operator) && method.Signature.Parameters.Count == 1 && - method.Signature.Parameters[0].Type.Name == nameof(ClientResult)) + method.Signature.Parameters[0].Type.Name == nameof(ClientResult) && + !method.EnclosingType.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Internal)) { return null; } diff --git a/codegen/generator/src/Visitors/PaginationVisitor.cs b/codegen/generator/src/Visitors/PaginationVisitor.cs new file mode 100644 index 000000000..070043845 --- /dev/null +++ b/codegen/generator/src/Visitors/PaginationVisitor.cs @@ -0,0 +1,100 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.TypeSpec.Generator.ClientModel; +using Microsoft.TypeSpec.Generator.ClientModel.Providers; +using Microsoft.TypeSpec.Generator.Expressions; +using Microsoft.TypeSpec.Generator.Input; +using Microsoft.TypeSpec.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Providers; +using Microsoft.TypeSpec.Generator.Snippets; +using Microsoft.TypeSpec.Generator.Statements; +using static OpenAILibraryPlugin.Visitors.VisitorHelpers; + +namespace OpenAILibraryPlugin.Visitors; + +/// +/// This visitor modifies GetRawPagesAsync methods to consider HasMore in addition to LastId when deciding whether to continue pagination. +/// +public class PaginationVisitor : ScmLibraryVisitor +{ + protected override MethodProvider? VisitMethod(MethodProvider method) + { + if (method.Signature.Name == "GetRawPagesAsync" && method.EnclosingType.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Internal)) + { + var statements = method.BodyStatements?.ToList() ?? new List(); + VisitExplodedMethodBodyStatements( + statements!, + statement => + { + if (statement is IfStatement) + { + return GetUpdatedIfStatement( + statement, + expression => + { + // Check if this is a binary expression with "==" operator + if (expression is ScopedApi scopedApi && scopedApi.Original is BinaryOperatorExpression binaryExpr && binaryExpr.Operator == "==") + { + // Check if left side is "nextToken" and right side is "null" + if (binaryExpr.Left is VariableExpression leftVar && + leftVar.Declaration.RequestedName == "nextToken" && + binaryExpr.Right is KeywordExpression rightKeyword && + rightKeyword.Keyword == "null") + { + // Create "hasMore == null" condition + var hasMoreNullCheck = new BinaryOperatorExpression( + "==", + new MemberExpression(null, "hasMore"), + new KeywordExpression("false", null)); + + // Return "nextToken == null || hasMore == null" + return new BinaryOperatorExpression("||", binaryExpr, hasMoreNullCheck); + } + } + return expression; + }, + "Plugin customization: add hasMore == false check to pagination condition"); + } + else if (statement is WhileStatement whileStatement) + { + var statementList = whileStatement.Body + .SelectMany(bodyStatement => bodyStatement) + .ToList(); + + for (int i = 0; i < statementList.Count; i++) + { + if (statementList[i] is ExpressionStatement expressionStatement && + expressionStatement.Expression is AssignmentExpression assignmentExpression && + assignmentExpression.Variable is VariableExpression variableExpression && + variableExpression.Declaration.RequestedName == "nextToken" && + assignmentExpression.Value is MemberExpression memberExpression && + memberExpression.MemberName == "LastId") + { + // Create a new assignment for hasMore + var hasMoreAssignment = new AssignmentExpression( + new DeclarationExpression(typeof(bool), "hasMore"), + new MemberExpression(memberExpression.Inner, "HasMore")); + + // Insert the new assignment before the existing one + statementList.Insert(i, new ExpressionStatement(hasMoreAssignment)); + statementList.Insert(i, new SingleLineCommentStatement("Plugin customization: add hasMore assignment")); + var updatedWhileStatement = new WhileStatement(whileStatement.Condition); + foreach (MethodBodyStatement bodyStatement in statementList) + { + updatedWhileStatement.Add(bodyStatement); + } + return updatedWhileStatement; + } + } + } + return statement; + }); + + method.Update(bodyStatements: statements); + return method; + } + + return base.VisitMethod(method); + } +} \ No newline at end of file diff --git a/codegen/generator/src/Visitors/VisitorHelpers.cs b/codegen/generator/src/Visitors/VisitorHelpers.cs index 7775bc709..c1c5bcee0 100644 --- a/codegen/generator/src/Visitors/VisitorHelpers.cs +++ b/codegen/generator/src/Visitors/VisitorHelpers.cs @@ -35,6 +35,20 @@ List foreachBodyStatements { // To do: traverse inside of "for" } + else if (statements[i] is WhileStatement whileStatement) + { + List whileBodyStatements + = whileStatement.Body + .SelectMany(bodyStatement => bodyStatement) + .ToList(); + VisitExplodedMethodBodyStatements(whileBodyStatements!, visitorFunc); + var newWhileStatement = new WhileStatement(whileStatement.Condition); + foreach (MethodBodyStatement bodyStatement in whileBodyStatements) + { + newWhileStatement.Add(bodyStatement); + } + statements[i] = newWhileStatement; + } } } diff --git a/src/Custom/Chat/ChatClient.Protocol.cs b/src/Custom/Chat/ChatClient.Protocol.cs index 40c25a767..30d6ab2ac 100644 --- a/src/Custom/Chat/ChatClient.Protocol.cs +++ b/src/Custom/Chat/ChatClient.Protocol.cs @@ -9,8 +9,6 @@ namespace OpenAI.Chat; /// The service client for the OpenAI Chat Completions endpoint. [CodeGenSuppress("GetChatCompletionMessagesAsync", typeof(string), typeof(string), typeof(int?), typeof(string), typeof(RequestOptions))] [CodeGenSuppress("GetChatCompletionMessages", typeof(string), typeof(string), typeof(int?), typeof(string), typeof(RequestOptions))] -[CodeGenSuppress("GetChatCompletionsAsync", typeof(string), typeof(int?), typeof(string), typeof(IDictionary), typeof(string), typeof(RequestOptions))] -[CodeGenSuppress("GetChatCompletions", typeof(string), typeof(int?), typeof(string), typeof(IDictionary), typeof(string), typeof(RequestOptions))] [CodeGenSuppress("UpdateChatCompletionAsync", typeof(string), typeof(BinaryContent), typeof(RequestOptions))] [CodeGenSuppress("UpdateChatCompletion", typeof(string), typeof(BinaryContent), typeof(RequestOptions))] public partial class ChatClient diff --git a/src/Custom/Chat/ChatClient.cs b/src/Custom/Chat/ChatClient.cs index f88d4bfe8..17352d668 100644 --- a/src/Custom/Chat/ChatClient.cs +++ b/src/Custom/Chat/ChatClient.cs @@ -22,8 +22,6 @@ namespace OpenAI.Chat; [CodeGenSuppress("CompleteChatAsync", typeof(ChatCompletionOptions), typeof(CancellationToken))] [CodeGenSuppress("GetChatCompletionMessages", typeof(string), typeof(string), typeof(int?), typeof(OpenAI.VectorStores.VectorStoreCollectionOrder?), typeof(CancellationToken))] [CodeGenSuppress("GetChatCompletionMessagesAsync", typeof(string), typeof(string), typeof(int?), typeof(OpenAI.VectorStores.VectorStoreCollectionOrder?), typeof(CancellationToken))] -[CodeGenSuppress("GetChatCompletions", typeof(string), typeof(int?), typeof(OpenAI.VectorStores.VectorStoreCollectionOrder?), typeof(IDictionary), typeof(string), typeof(CancellationToken))] -[CodeGenSuppress("GetChatCompletionsAsync", typeof(string), typeof(int?), typeof(OpenAI.VectorStores.VectorStoreCollectionOrder?), typeof(IDictionary), typeof(string), typeof(CancellationToken))] [CodeGenSuppress("UpdateChatCompletion", typeof(string), typeof(IDictionary), typeof(CancellationToken))] [CodeGenSuppress("UpdateChatCompletionAsync", typeof(string), typeof(IDictionary), typeof(CancellationToken))] public partial class ChatClient diff --git a/src/Custom/Containers/Internal/GeneratorStubs.cs b/src/Custom/Containers/Internal/GeneratorStubs.cs index 622c7c90c..efdf68fe0 100644 --- a/src/Custom/Containers/Internal/GeneratorStubs.cs +++ b/src/Custom/Containers/Internal/GeneratorStubs.cs @@ -14,22 +14,10 @@ namespace OpenAI.Containers; [CodeGenType("ContainerListResource")] internal partial class InternalContainerListResource { - public static explicit operator InternalContainerListResource(ClientResult result) - { - using PipelineResponse response = result.GetRawResponse(); - using JsonDocument document = JsonDocument.Parse(response.Content); - return DeserializeInternalContainerListResource(document.RootElement, ModelSerializationExtensions.WireOptions); - } } [CodeGenType("ContainerResource")] internal partial class InternalContainerResource { - public static explicit operator InternalContainerResource(ClientResult result) - { - using PipelineResponse response = result.GetRawResponse(); - using JsonDocument document = JsonDocument.Parse(response.Content); - return DeserializeInternalContainerResource(document.RootElement, ModelSerializationExtensions.WireOptions); - } } [CodeGenType("ContainerResourceExpiresAfter")] internal partial class InternalContainerResourceExpiresAfter {} [CodeGenType("CreateContainerBody")] internal partial class InternalCreateContainerBody @@ -47,41 +35,17 @@ public static implicit operator BinaryContent(InternalCreateContainerBody intern [CodeGenType("DeleteContainerResponse")] internal partial class InternalDeleteContainerResponse { - public static explicit operator InternalDeleteContainerResponse(ClientResult result) - { - using PipelineResponse response = result.GetRawResponse(); - using JsonDocument document = JsonDocument.Parse(response.Content); - return DeserializeInternalDeleteContainerResponse(document.RootElement, ModelSerializationExtensions.WireOptions); - } } [CodeGenType("CreateContainerFileBody")] internal partial class InternalCreateContainerFileBody {} [CodeGenType("ContainerFileResource")] internal partial class InternalContainerFileResource { - public static explicit operator InternalContainerFileResource(ClientResult result) - { - using PipelineResponse response = result.GetRawResponse(); - using JsonDocument document = JsonDocument.Parse(response.Content); - return DeserializeInternalContainerFileResource(document.RootElement, ModelSerializationExtensions.WireOptions); - } } [CodeGenType("ContainerFileListResource")] internal partial class InternalContainerFileListResource { - public static explicit operator InternalContainerFileListResource(ClientResult result) - { - using PipelineResponse response = result.GetRawResponse(); - using JsonDocument document = JsonDocument.Parse(response.Content); - return DeserializeInternalContainerFileListResource(document.RootElement, ModelSerializationExtensions.WireOptions); - } } [CodeGenType("DeleteContainerFileResponse")] internal partial class InternalDeleteContainerFileResponse { - public static explicit operator InternalDeleteContainerFileResponse(ClientResult result) - { - using PipelineResponse response = result.GetRawResponse(); - using JsonDocument document = JsonDocument.Parse(response.Content); - return DeserializeInternalDeleteContainerFileResponse(document.RootElement, ModelSerializationExtensions.WireOptions); - } } \ No newline at end of file diff --git a/src/Custom/Files/Internal/GeneratorStubs.cs b/src/Custom/Files/Internal/GeneratorStubs.cs index cf854c952..a85d22a66 100644 --- a/src/Custom/Files/Internal/GeneratorStubs.cs +++ b/src/Custom/Files/Internal/GeneratorStubs.cs @@ -38,12 +38,6 @@ public static implicit operator BinaryContent(InternalCreateUploadRequest intern [CodeGenType("Upload")] internal partial class InternalUpload { - public static explicit operator InternalUpload(ClientResult result) - { - using PipelineResponse response = result.GetRawResponse(); - using JsonDocument document = JsonDocument.Parse(response.Content); - return DeserializeInternalUpload(document.RootElement, ModelSerializationExtensions.WireOptions); - } } [CodeGenType("UploadObject")] internal readonly partial struct InternalUploadObject { } [CodeGenType("UploadPart")] internal partial class InternalUploadPart { } diff --git a/src/Custom/Graders/Internal/GeneratorStubs.cs b/src/Custom/Graders/Internal/GeneratorStubs.cs index 92445a65c..f7f51e52c 100644 --- a/src/Custom/Graders/Internal/GeneratorStubs.cs +++ b/src/Custom/Graders/Internal/GeneratorStubs.cs @@ -41,12 +41,6 @@ public static explicit operator InternalRunGraderRequest(ClientResult result) [CodeGenType("RunGraderResponse")] internal partial class InternalRunGraderResponse { - public static explicit operator InternalRunGraderResponse(ClientResult result) - { - using PipelineResponse response = result.GetRawResponse(); - using JsonDocument document = JsonDocument.Parse(response.Content); - return DeserializeInternalRunGraderResponse(document.RootElement, ModelSerializationExtensions.WireOptions); - } } [CodeGenType("RunGraderResponseMetadata")] internal partial class InternalRunGraderResponseMetadata {} [CodeGenType("RunGraderResponseMetadataErrors")] internal partial class InternalRunGraderResponseMetadataErrors {} @@ -72,10 +66,4 @@ public static explicit operator InternalValidateGraderRequest(ClientResult resul [CodeGenType("ValidateGraderResponse")] internal partial class InternalValidateGraderResponse { - public static explicit operator InternalValidateGraderResponse(ClientResult result) - { - using PipelineResponse response = result.GetRawResponse(); - using JsonDocument document = JsonDocument.Parse(response.Content); - return DeserializeInternalValidateGraderResponse(document.RootElement, ModelSerializationExtensions.WireOptions); - } } diff --git a/src/Custom/LegacyCompletions/Internal/GeneratorStubs.cs b/src/Custom/LegacyCompletions/Internal/GeneratorStubs.cs index aeaecf512..744cad848 100644 --- a/src/Custom/LegacyCompletions/Internal/GeneratorStubs.cs +++ b/src/Custom/LegacyCompletions/Internal/GeneratorStubs.cs @@ -26,12 +26,6 @@ internal readonly partial struct InternalCreateCompletionRequestModel { } [CodeGenType("CreateCompletionResponse")] internal partial class InternalCreateCompletionResponse { - public static explicit operator InternalCreateCompletionResponse(ClientResult result) - { - using PipelineResponse response = result.GetRawResponse(); - using JsonDocument document = JsonDocument.Parse(response.Content); - return DeserializeInternalCreateCompletionResponse(document.RootElement, ModelSerializationExtensions.WireOptions); - } } [CodeGenType("CreateCompletionResponseChoice")] diff --git a/src/Generated/ChatClient.cs b/src/Generated/ChatClient.cs index 5facc9551..faf7c4572 100644 --- a/src/Generated/ChatClient.cs +++ b/src/Generated/ChatClient.cs @@ -5,8 +5,12 @@ using System; using System.ClientModel; using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Threading; using System.Threading.Tasks; using OpenAI; +using OpenAI.VectorStores; namespace OpenAI.Chat { @@ -20,6 +24,58 @@ protected ChatClient() public ClientPipeline Pipeline { get; } + [Experimental("OPENAI001")] + public virtual CollectionResult GetChatCompletions(string after, int? limit, string order, IDictionary metadata, string model, RequestOptions options) + { + return new ChatClientGetChatCompletionsCollectionResult( + this, + after, + limit, + order, + metadata, + model, + options); + } + + [Experimental("OPENAI001")] + public virtual AsyncCollectionResult GetChatCompletionsAsync(string after, int? limit, string order, IDictionary metadata, string model, RequestOptions options) + { + return new ChatClientGetChatCompletionsAsyncCollectionResult( + this, + after, + limit, + order, + metadata, + model, + options); + } + + [Experimental("OPENAI001")] + public virtual CollectionResult GetChatCompletions(string after = default, int? limit = default, VectorStoreCollectionOrder? order = default, IDictionary metadata = default, string model = default, CancellationToken cancellationToken = default) + { + return new ChatClientGetChatCompletionsCollectionResultOfT( + this, + after, + limit, + order?.ToString(), + metadata, + model, + cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null); + } + + [Experimental("OPENAI001")] + public virtual AsyncCollectionResult GetChatCompletionsAsync(string after = default, int? limit = default, VectorStoreCollectionOrder? order = default, IDictionary metadata = default, string model = default, CancellationToken cancellationToken = default) + { + return new ChatClientGetChatCompletionsAsyncCollectionResultOfT( + this, + after, + limit, + order?.ToString(), + metadata, + model, + cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null); + } + public virtual ClientResult CompleteChat(BinaryContent content, RequestOptions options = null) { Argument.AssertNotNull(content, nameof(content)); diff --git a/src/Generated/ChatClientGetChatCompletionsAsyncCollectionResult.cs b/src/Generated/ChatClientGetChatCompletionsAsyncCollectionResult.cs new file mode 100644 index 000000000..5740521e7 --- /dev/null +++ b/src/Generated/ChatClientGetChatCompletionsAsyncCollectionResult.cs @@ -0,0 +1,67 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; + +namespace OpenAI.Chat +{ + internal partial class ChatClientGetChatCompletionsAsyncCollectionResult : AsyncCollectionResult + { + private readonly ChatClient _client; + private readonly string _after; + private readonly int? _limit; + private readonly string _order; + private readonly IDictionary _metadata; + private readonly string _model; + private readonly RequestOptions _options; + + public ChatClientGetChatCompletionsAsyncCollectionResult(ChatClient client, string after, int? limit, string order, IDictionary metadata, string model, RequestOptions options) + { + _client = client; + _after = after; + _limit = limit; + _order = order; + _metadata = metadata; + _model = model; + _options = options; + } + + public override async IAsyncEnumerable GetRawPagesAsync() + { + PipelineMessage message = _client.CreateGetChatCompletionsRequest(_after, _limit, _order, _metadata, _model, _options); + string nextToken = null; + while (true) + { + ClientResult result = ClientResult.FromResponse(await _client.Pipeline.ProcessMessageAsync(message, _options).ConfigureAwait(false)); + yield return result; + + // Plugin customization: add hasMore assignment + bool hasMore = ((InternalChatCompletionList)result).HasMore; + nextToken = ((InternalChatCompletionList)result).LastId; + // Plugin customization: add hasMore == false check to pagination condition + if (nextToken == null || hasMore == false) + { + yield break; + } + message = _client.CreateGetChatCompletionsRequest(nextToken, _limit, _order, _metadata, _model, _options); + } + } + + public override ContinuationToken GetContinuationToken(ClientResult page) + { + string nextPage = ((InternalChatCompletionList)page).LastId; + if (nextPage != null) + { + return ContinuationToken.FromBytes(BinaryData.FromString(nextPage)); + } + else + { + return null; + } + } + } +} diff --git a/src/Generated/ChatClientGetChatCompletionsAsyncCollectionResultOfT.cs b/src/Generated/ChatClientGetChatCompletionsAsyncCollectionResultOfT.cs new file mode 100644 index 000000000..d486452b1 --- /dev/null +++ b/src/Generated/ChatClientGetChatCompletionsAsyncCollectionResultOfT.cs @@ -0,0 +1,77 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace OpenAI.Chat +{ + internal partial class ChatClientGetChatCompletionsAsyncCollectionResultOfT : AsyncCollectionResult + { + private readonly ChatClient _client; + private readonly string _after; + private readonly int? _limit; + private readonly string _order; + private readonly IDictionary _metadata; + private readonly string _model; + private readonly RequestOptions _options; + + public ChatClientGetChatCompletionsAsyncCollectionResultOfT(ChatClient client, string after, int? limit, string order, IDictionary metadata, string model, RequestOptions options) + { + _client = client; + _after = after; + _limit = limit; + _order = order; + _metadata = metadata; + _model = model; + _options = options; + } + + public override async IAsyncEnumerable GetRawPagesAsync() + { + PipelineMessage message = _client.CreateGetChatCompletionsRequest(_after, _limit, _order, _metadata, _model, _options); + string nextToken = null; + while (true) + { + ClientResult result = ClientResult.FromResponse(await _client.Pipeline.ProcessMessageAsync(message, _options).ConfigureAwait(false)); + yield return result; + + // Plugin customization: add hasMore assignment + bool hasMore = ((InternalChatCompletionList)result).HasMore; + nextToken = ((InternalChatCompletionList)result).LastId; + // Plugin customization: add hasMore == false check to pagination condition + if (nextToken == null || hasMore == false) + { + yield break; + } + message = _client.CreateGetChatCompletionsRequest(nextToken, _limit, _order, _metadata, _model, _options); + } + } + + public override ContinuationToken GetContinuationToken(ClientResult page) + { + string nextPage = ((InternalChatCompletionList)page).LastId; + if (nextPage != null) + { + return ContinuationToken.FromBytes(BinaryData.FromString(nextPage)); + } + else + { + return null; + } + } + + protected override async IAsyncEnumerable GetValuesFromPageAsync(ClientResult page) + { + foreach (ChatCompletion item in ((InternalChatCompletionList)page).Data) + { + yield return item; + await Task.Yield(); + } + } + } +} diff --git a/src/Generated/ChatClientGetChatCompletionsCollectionResult.cs b/src/Generated/ChatClientGetChatCompletionsCollectionResult.cs new file mode 100644 index 000000000..f62c24cc9 --- /dev/null +++ b/src/Generated/ChatClientGetChatCompletionsCollectionResult.cs @@ -0,0 +1,64 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; + +namespace OpenAI.Chat +{ + internal partial class ChatClientGetChatCompletionsCollectionResult : CollectionResult + { + private readonly ChatClient _client; + private readonly string _after; + private readonly int? _limit; + private readonly string _order; + private readonly IDictionary _metadata; + private readonly string _model; + private readonly RequestOptions _options; + + public ChatClientGetChatCompletionsCollectionResult(ChatClient client, string after, int? limit, string order, IDictionary metadata, string model, RequestOptions options) + { + _client = client; + _after = after; + _limit = limit; + _order = order; + _metadata = metadata; + _model = model; + _options = options; + } + + public override IEnumerable GetRawPages() + { + PipelineMessage message = _client.CreateGetChatCompletionsRequest(_after, _limit, _order, _metadata, _model, _options); + string nextToken = null; + while (true) + { + ClientResult result = ClientResult.FromResponse(_client.Pipeline.ProcessMessage(message, _options)); + yield return result; + + nextToken = ((InternalChatCompletionList)result).LastId; + if (nextToken == null) + { + yield break; + } + message = _client.CreateGetChatCompletionsRequest(nextToken, _limit, _order, _metadata, _model, _options); + } + } + + public override ContinuationToken GetContinuationToken(ClientResult page) + { + string nextPage = ((InternalChatCompletionList)page).LastId; + if (nextPage != null) + { + return ContinuationToken.FromBytes(BinaryData.FromString(nextPage)); + } + else + { + return null; + } + } + } +} diff --git a/src/Generated/ChatClientGetChatCompletionsCollectionResultOfT.cs b/src/Generated/ChatClientGetChatCompletionsCollectionResultOfT.cs new file mode 100644 index 000000000..9e3ba0378 --- /dev/null +++ b/src/Generated/ChatClientGetChatCompletionsCollectionResultOfT.cs @@ -0,0 +1,69 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Collections.Generic; + +namespace OpenAI.Chat +{ + internal partial class ChatClientGetChatCompletionsCollectionResultOfT : CollectionResult + { + private readonly ChatClient _client; + private readonly string _after; + private readonly int? _limit; + private readonly string _order; + private readonly IDictionary _metadata; + private readonly string _model; + private readonly RequestOptions _options; + + public ChatClientGetChatCompletionsCollectionResultOfT(ChatClient client, string after, int? limit, string order, IDictionary metadata, string model, RequestOptions options) + { + _client = client; + _after = after; + _limit = limit; + _order = order; + _metadata = metadata; + _model = model; + _options = options; + } + + public override IEnumerable GetRawPages() + { + PipelineMessage message = _client.CreateGetChatCompletionsRequest(_after, _limit, _order, _metadata, _model, _options); + string nextToken = null; + while (true) + { + ClientResult result = ClientResult.FromResponse(_client.Pipeline.ProcessMessage(message, _options)); + yield return result; + + nextToken = ((InternalChatCompletionList)result).LastId; + if (nextToken == null) + { + yield break; + } + message = _client.CreateGetChatCompletionsRequest(nextToken, _limit, _order, _metadata, _model, _options); + } + } + + public override ContinuationToken GetContinuationToken(ClientResult page) + { + string nextPage = ((InternalChatCompletionList)page).LastId; + if (nextPage != null) + { + return ContinuationToken.FromBytes(BinaryData.FromString(nextPage)); + } + else + { + return null; + } + } + + protected override IEnumerable GetValuesFromPage(ClientResult page) + { + return ((InternalChatCompletionList)page).Data; + } + } +} diff --git a/src/Generated/Models/Assistants/InternalListAssistantsResponse.Serialization.cs b/src/Generated/Models/Assistants/InternalListAssistantsResponse.Serialization.cs index 355041181..dd0e50630 100644 --- a/src/Generated/Models/Assistants/InternalListAssistantsResponse.Serialization.cs +++ b/src/Generated/Models/Assistants/InternalListAssistantsResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -184,5 +185,12 @@ protected virtual InternalListAssistantsResponse PersistableModelCreateCore(Bina } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalListAssistantsResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalListAssistantsResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Assistants/InternalListMessagesResponse.Serialization.cs b/src/Generated/Models/Assistants/InternalListMessagesResponse.Serialization.cs index 089a43108..a4ce553b5 100644 --- a/src/Generated/Models/Assistants/InternalListMessagesResponse.Serialization.cs +++ b/src/Generated/Models/Assistants/InternalListMessagesResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -184,5 +185,12 @@ protected virtual InternalListMessagesResponse PersistableModelCreateCore(Binary } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalListMessagesResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalListMessagesResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Assistants/InternalListRunStepsResponse.Serialization.cs b/src/Generated/Models/Assistants/InternalListRunStepsResponse.Serialization.cs index 1709103c6..739661052 100644 --- a/src/Generated/Models/Assistants/InternalListRunStepsResponse.Serialization.cs +++ b/src/Generated/Models/Assistants/InternalListRunStepsResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -184,5 +185,12 @@ protected virtual InternalListRunStepsResponse PersistableModelCreateCore(Binary } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalListRunStepsResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalListRunStepsResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Assistants/InternalListRunsResponse.Serialization.cs b/src/Generated/Models/Assistants/InternalListRunsResponse.Serialization.cs index a02f126fd..6abb47d79 100644 --- a/src/Generated/Models/Assistants/InternalListRunsResponse.Serialization.cs +++ b/src/Generated/Models/Assistants/InternalListRunsResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -184,5 +185,12 @@ protected virtual InternalListRunsResponse PersistableModelCreateCore(BinaryData } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalListRunsResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalListRunsResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Batch/InternalBatchJob.Serialization.cs b/src/Generated/Models/Batch/InternalBatchJob.Serialization.cs index b63b87acd..7a87b100f 100644 --- a/src/Generated/Models/Batch/InternalBatchJob.Serialization.cs +++ b/src/Generated/Models/Batch/InternalBatchJob.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -428,5 +429,12 @@ protected virtual InternalBatchJob PersistableModelCreateCore(BinaryData data, M } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalBatchJob(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalBatchJob(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Batch/InternalListBatchesResponse.Serialization.cs b/src/Generated/Models/Batch/InternalListBatchesResponse.Serialization.cs index 45fe4af08..4bc86c18f 100644 --- a/src/Generated/Models/Batch/InternalListBatchesResponse.Serialization.cs +++ b/src/Generated/Models/Batch/InternalListBatchesResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -183,5 +184,12 @@ protected virtual InternalListBatchesResponse PersistableModelCreateCore(BinaryD } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalListBatchesResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalListBatchesResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Chat/InternalChatCompletionList.Serialization.cs b/src/Generated/Models/Chat/InternalChatCompletionList.Serialization.cs index fe9235048..3871055d7 100644 --- a/src/Generated/Models/Chat/InternalChatCompletionList.Serialization.cs +++ b/src/Generated/Models/Chat/InternalChatCompletionList.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -183,5 +184,12 @@ protected virtual InternalChatCompletionList PersistableModelCreateCore(BinaryDa } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalChatCompletionList(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalChatCompletionList(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Chat/InternalChatCompletionMessageList.Serialization.cs b/src/Generated/Models/Chat/InternalChatCompletionMessageList.Serialization.cs index 21bf965c2..4318e9032 100644 --- a/src/Generated/Models/Chat/InternalChatCompletionMessageList.Serialization.cs +++ b/src/Generated/Models/Chat/InternalChatCompletionMessageList.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -183,5 +184,12 @@ protected virtual InternalChatCompletionMessageList PersistableModelCreateCore(B } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalChatCompletionMessageList(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalChatCompletionMessageList(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Containers/InternalContainerFileListResource.Serialization.cs b/src/Generated/Models/Containers/InternalContainerFileListResource.Serialization.cs index c9800822d..df7cfa177 100644 --- a/src/Generated/Models/Containers/InternalContainerFileListResource.Serialization.cs +++ b/src/Generated/Models/Containers/InternalContainerFileListResource.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -183,5 +184,12 @@ protected virtual InternalContainerFileListResource PersistableModelCreateCore(B } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalContainerFileListResource(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalContainerFileListResource(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Containers/InternalContainerFileResource.Serialization.cs b/src/Generated/Models/Containers/InternalContainerFileResource.Serialization.cs index 1b06bd61c..ce7c8c769 100644 --- a/src/Generated/Models/Containers/InternalContainerFileResource.Serialization.cs +++ b/src/Generated/Models/Containers/InternalContainerFileResource.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -197,5 +198,12 @@ protected virtual InternalContainerFileResource PersistableModelCreateCore(Binar } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalContainerFileResource(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalContainerFileResource(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Containers/InternalContainerListResource.Serialization.cs b/src/Generated/Models/Containers/InternalContainerListResource.Serialization.cs index e3903d016..3fa84010f 100644 --- a/src/Generated/Models/Containers/InternalContainerListResource.Serialization.cs +++ b/src/Generated/Models/Containers/InternalContainerListResource.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -183,5 +184,12 @@ protected virtual InternalContainerListResource PersistableModelCreateCore(Binar } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalContainerListResource(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalContainerListResource(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Containers/InternalContainerResource.Serialization.cs b/src/Generated/Models/Containers/InternalContainerResource.Serialization.cs index 5f25abb98..b7df10aa4 100644 --- a/src/Generated/Models/Containers/InternalContainerResource.Serialization.cs +++ b/src/Generated/Models/Containers/InternalContainerResource.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -189,5 +190,12 @@ protected virtual InternalContainerResource PersistableModelCreateCore(BinaryDat } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalContainerResource(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalContainerResource(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Containers/InternalDeleteContainerFileResponse.Serialization.cs b/src/Generated/Models/Containers/InternalDeleteContainerFileResponse.Serialization.cs index f66468ecd..7a454ce77 100644 --- a/src/Generated/Models/Containers/InternalDeleteContainerFileResponse.Serialization.cs +++ b/src/Generated/Models/Containers/InternalDeleteContainerFileResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -145,5 +146,12 @@ protected virtual InternalDeleteContainerFileResponse PersistableModelCreateCore } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalDeleteContainerFileResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalDeleteContainerFileResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Containers/InternalDeleteContainerResponse.Serialization.cs b/src/Generated/Models/Containers/InternalDeleteContainerResponse.Serialization.cs index 708fe805e..cb70ec8a7 100644 --- a/src/Generated/Models/Containers/InternalDeleteContainerResponse.Serialization.cs +++ b/src/Generated/Models/Containers/InternalDeleteContainerResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -145,5 +146,12 @@ protected virtual InternalDeleteContainerResponse PersistableModelCreateCore(Bin } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalDeleteContainerResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalDeleteContainerResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Evals/InternalDeleteEvalResponse.Serialization.cs b/src/Generated/Models/Evals/InternalDeleteEvalResponse.Serialization.cs index 074b57d44..bbffa3f0d 100644 --- a/src/Generated/Models/Evals/InternalDeleteEvalResponse.Serialization.cs +++ b/src/Generated/Models/Evals/InternalDeleteEvalResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -145,5 +146,12 @@ protected virtual InternalDeleteEvalResponse PersistableModelCreateCore(BinaryDa } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalDeleteEvalResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalDeleteEvalResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Evals/InternalDeleteEvalRunResponse.Serialization.cs b/src/Generated/Models/Evals/InternalDeleteEvalRunResponse.Serialization.cs index 4f0d872cc..86faf0d9f 100644 --- a/src/Generated/Models/Evals/InternalDeleteEvalRunResponse.Serialization.cs +++ b/src/Generated/Models/Evals/InternalDeleteEvalRunResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -145,5 +146,12 @@ protected virtual InternalDeleteEvalRunResponse PersistableModelCreateCore(Binar } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalDeleteEvalRunResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalDeleteEvalRunResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Evals/InternalEval.Serialization.cs b/src/Generated/Models/Evals/InternalEval.Serialization.cs index f3c2c1a0f..f797abc57 100644 --- a/src/Generated/Models/Evals/InternalEval.Serialization.cs +++ b/src/Generated/Models/Evals/InternalEval.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -254,5 +255,12 @@ protected virtual InternalEval PersistableModelCreateCore(BinaryData data, Model } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalEval(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalEval(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Evals/InternalEvalList.Serialization.cs b/src/Generated/Models/Evals/InternalEvalList.Serialization.cs index 467bd927f..75418e07a 100644 --- a/src/Generated/Models/Evals/InternalEvalList.Serialization.cs +++ b/src/Generated/Models/Evals/InternalEvalList.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -183,5 +184,12 @@ protected virtual InternalEvalList PersistableModelCreateCore(BinaryData data, M } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalEvalList(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalEvalList(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Evals/InternalEvalRun.Serialization.cs b/src/Generated/Models/Evals/InternalEvalRun.Serialization.cs index adff0abc6..46edc28d5 100644 --- a/src/Generated/Models/Evals/InternalEvalRun.Serialization.cs +++ b/src/Generated/Models/Evals/InternalEvalRun.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -336,5 +337,12 @@ protected virtual InternalEvalRun PersistableModelCreateCore(BinaryData data, Mo } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalEvalRun(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalEvalRun(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Evals/InternalEvalRunList.Serialization.cs b/src/Generated/Models/Evals/InternalEvalRunList.Serialization.cs index af0ce4eab..4bfce8682 100644 --- a/src/Generated/Models/Evals/InternalEvalRunList.Serialization.cs +++ b/src/Generated/Models/Evals/InternalEvalRunList.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -183,5 +184,12 @@ protected virtual InternalEvalRunList PersistableModelCreateCore(BinaryData data } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalEvalRunList(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalEvalRunList(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Evals/InternalEvalRunOutputItem.Serialization.cs b/src/Generated/Models/Evals/InternalEvalRunOutputItem.Serialization.cs index 840ec8a0b..d2641487f 100644 --- a/src/Generated/Models/Evals/InternalEvalRunOutputItem.Serialization.cs +++ b/src/Generated/Models/Evals/InternalEvalRunOutputItem.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -315,5 +316,12 @@ protected virtual InternalEvalRunOutputItem PersistableModelCreateCore(BinaryDat } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalEvalRunOutputItem(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalEvalRunOutputItem(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Evals/InternalEvalRunOutputItemList.Serialization.cs b/src/Generated/Models/Evals/InternalEvalRunOutputItemList.Serialization.cs index f008b5504..4ed0161b9 100644 --- a/src/Generated/Models/Evals/InternalEvalRunOutputItemList.Serialization.cs +++ b/src/Generated/Models/Evals/InternalEvalRunOutputItemList.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -183,5 +184,12 @@ protected virtual InternalEvalRunOutputItemList PersistableModelCreateCore(Binar } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalEvalRunOutputItemList(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalEvalRunOutputItemList(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Files/InternalUpload.Serialization.cs b/src/Generated/Models/Files/InternalUpload.Serialization.cs index b793b213d..09c441ebc 100644 --- a/src/Generated/Models/Files/InternalUpload.Serialization.cs +++ b/src/Generated/Models/Files/InternalUpload.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -226,5 +227,12 @@ protected virtual InternalUpload PersistableModelCreateCore(BinaryData data, Mod } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalUpload(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalUpload(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Files/InternalUploadPart.Serialization.cs b/src/Generated/Models/Files/InternalUploadPart.Serialization.cs index 8883ad57b..cda4b7c95 100644 --- a/src/Generated/Models/Files/InternalUploadPart.Serialization.cs +++ b/src/Generated/Models/Files/InternalUploadPart.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -156,5 +157,12 @@ protected virtual InternalUploadPart PersistableModelCreateCore(BinaryData data, } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalUploadPart(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalUploadPart(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/FineTuning/InternalDeleteFineTuningCheckpointPermissionResponse.Serialization.cs b/src/Generated/Models/FineTuning/InternalDeleteFineTuningCheckpointPermissionResponse.Serialization.cs index 74cc1decf..4988068a8 100644 --- a/src/Generated/Models/FineTuning/InternalDeleteFineTuningCheckpointPermissionResponse.Serialization.cs +++ b/src/Generated/Models/FineTuning/InternalDeleteFineTuningCheckpointPermissionResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -145,5 +146,12 @@ protected virtual InternalDeleteFineTuningCheckpointPermissionResponse Persistab } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalDeleteFineTuningCheckpointPermissionResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalDeleteFineTuningCheckpointPermissionResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/FineTuning/InternalFineTuningJob.Serialization.cs b/src/Generated/Models/FineTuning/InternalFineTuningJob.Serialization.cs index b97c9b880..e2dddfa68 100644 --- a/src/Generated/Models/FineTuning/InternalFineTuningJob.Serialization.cs +++ b/src/Generated/Models/FineTuning/InternalFineTuningJob.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -498,5 +499,12 @@ protected virtual InternalFineTuningJob PersistableModelCreateCore(BinaryData da } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalFineTuningJob(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalFineTuningJob(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/FineTuning/InternalListFineTuningCheckpointPermissionResponse.Serialization.cs b/src/Generated/Models/FineTuning/InternalListFineTuningCheckpointPermissionResponse.Serialization.cs index ba7dab38c..dd5c8274c 100644 --- a/src/Generated/Models/FineTuning/InternalListFineTuningCheckpointPermissionResponse.Serialization.cs +++ b/src/Generated/Models/FineTuning/InternalListFineTuningCheckpointPermissionResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -193,5 +194,12 @@ protected virtual InternalListFineTuningCheckpointPermissionResponse Persistable } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalListFineTuningCheckpointPermissionResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalListFineTuningCheckpointPermissionResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/FineTuning/InternalListFineTuningJobCheckpointsResponse.Serialization.cs b/src/Generated/Models/FineTuning/InternalListFineTuningJobCheckpointsResponse.Serialization.cs index 035c35112..e5b209b77 100644 --- a/src/Generated/Models/FineTuning/InternalListFineTuningJobCheckpointsResponse.Serialization.cs +++ b/src/Generated/Models/FineTuning/InternalListFineTuningJobCheckpointsResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -193,5 +194,12 @@ protected virtual InternalListFineTuningJobCheckpointsResponse PersistableModelC } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalListFineTuningJobCheckpointsResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalListFineTuningJobCheckpointsResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/FineTuning/InternalListFineTuningJobEventsResponse.Serialization.cs b/src/Generated/Models/FineTuning/InternalListFineTuningJobEventsResponse.Serialization.cs index 68e008509..6f56e35f9 100644 --- a/src/Generated/Models/FineTuning/InternalListFineTuningJobEventsResponse.Serialization.cs +++ b/src/Generated/Models/FineTuning/InternalListFineTuningJobEventsResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -155,5 +156,12 @@ protected virtual InternalListFineTuningJobEventsResponse PersistableModelCreate } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalListFineTuningJobEventsResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalListFineTuningJobEventsResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/FineTuning/InternalListPaginatedFineTuningJobsResponse.Serialization.cs b/src/Generated/Models/FineTuning/InternalListPaginatedFineTuningJobsResponse.Serialization.cs index 6e9277e4e..815408341 100644 --- a/src/Generated/Models/FineTuning/InternalListPaginatedFineTuningJobsResponse.Serialization.cs +++ b/src/Generated/Models/FineTuning/InternalListPaginatedFineTuningJobsResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -155,5 +156,12 @@ protected virtual InternalListPaginatedFineTuningJobsResponse PersistableModelCr } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalListPaginatedFineTuningJobsResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalListPaginatedFineTuningJobsResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Graders/InternalRunGraderResponse.Serialization.cs b/src/Generated/Models/Graders/InternalRunGraderResponse.Serialization.cs index c5199852c..2f013bebc 100644 --- a/src/Generated/Models/Graders/InternalRunGraderResponse.Serialization.cs +++ b/src/Generated/Models/Graders/InternalRunGraderResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -170,5 +171,12 @@ protected virtual InternalRunGraderResponse PersistableModelCreateCore(BinaryDat } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalRunGraderResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalRunGraderResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Graders/InternalValidateGraderResponse.Serialization.cs b/src/Generated/Models/Graders/InternalValidateGraderResponse.Serialization.cs index 9da1c49e7..0f87f692d 100644 --- a/src/Generated/Models/Graders/InternalValidateGraderResponse.Serialization.cs +++ b/src/Generated/Models/Graders/InternalValidateGraderResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -130,5 +131,12 @@ protected virtual InternalValidateGraderResponse PersistableModelCreateCore(Bina } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalValidateGraderResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalValidateGraderResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/LegacyCompletions/InternalCreateCompletionResponse.Serialization.cs b/src/Generated/Models/LegacyCompletions/InternalCreateCompletionResponse.Serialization.cs index 6c2ff891a..7538d6288 100644 --- a/src/Generated/Models/LegacyCompletions/InternalCreateCompletionResponse.Serialization.cs +++ b/src/Generated/Models/LegacyCompletions/InternalCreateCompletionResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -212,5 +213,12 @@ protected virtual InternalCreateCompletionResponse PersistableModelCreateCore(Bi } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalCreateCompletionResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalCreateCompletionResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Realtime/InternalRealtimeSessionCreateResponse.Serialization.cs b/src/Generated/Models/Realtime/InternalRealtimeSessionCreateResponse.Serialization.cs index ca291a979..cae237de8 100644 --- a/src/Generated/Models/Realtime/InternalRealtimeSessionCreateResponse.Serialization.cs +++ b/src/Generated/Models/Realtime/InternalRealtimeSessionCreateResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -360,5 +361,12 @@ protected virtual InternalRealtimeSessionCreateResponse PersistableModelCreateCo } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalRealtimeSessionCreateResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalRealtimeSessionCreateResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Realtime/InternalRealtimeTranscriptionSessionCreateResponse.Serialization.cs b/src/Generated/Models/Realtime/InternalRealtimeTranscriptionSessionCreateResponse.Serialization.cs index ede2199db..ebb6c1a31 100644 --- a/src/Generated/Models/Realtime/InternalRealtimeTranscriptionSessionCreateResponse.Serialization.cs +++ b/src/Generated/Models/Realtime/InternalRealtimeTranscriptionSessionCreateResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -195,5 +196,12 @@ protected virtual InternalRealtimeTranscriptionSessionCreateResponse Persistable } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalRealtimeTranscriptionSessionCreateResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalRealtimeTranscriptionSessionCreateResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/Responses/InternalResponseItemList.Serialization.cs b/src/Generated/Models/Responses/InternalResponseItemList.Serialization.cs index 288436848..fd000f146 100644 --- a/src/Generated/Models/Responses/InternalResponseItemList.Serialization.cs +++ b/src/Generated/Models/Responses/InternalResponseItemList.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -183,5 +184,12 @@ protected virtual InternalResponseItemList PersistableModelCreateCore(BinaryData } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalResponseItemList(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalResponseItemList(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/VectorStores/InternalListVectorStoreFilesResponse.Serialization.cs b/src/Generated/Models/VectorStores/InternalListVectorStoreFilesResponse.Serialization.cs index 3f16044ee..02b61833d 100644 --- a/src/Generated/Models/VectorStores/InternalListVectorStoreFilesResponse.Serialization.cs +++ b/src/Generated/Models/VectorStores/InternalListVectorStoreFilesResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -184,5 +185,12 @@ protected virtual InternalListVectorStoreFilesResponse PersistableModelCreateCor } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalListVectorStoreFilesResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalListVectorStoreFilesResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/VectorStores/InternalListVectorStoresResponse.Serialization.cs b/src/Generated/Models/VectorStores/InternalListVectorStoresResponse.Serialization.cs index 5e5a3f70e..c4442b048 100644 --- a/src/Generated/Models/VectorStores/InternalListVectorStoresResponse.Serialization.cs +++ b/src/Generated/Models/VectorStores/InternalListVectorStoresResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -184,5 +185,12 @@ protected virtual InternalListVectorStoresResponse PersistableModelCreateCore(Bi } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalListVectorStoresResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalListVectorStoresResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/VectorStores/InternalVectorStoreFileContentResponse.Serialization.cs b/src/Generated/Models/VectorStores/InternalVectorStoreFileContentResponse.Serialization.cs index 2b9dab0d8..8cc2e1074 100644 --- a/src/Generated/Models/VectorStores/InternalVectorStoreFileContentResponse.Serialization.cs +++ b/src/Generated/Models/VectorStores/InternalVectorStoreFileContentResponse.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -178,5 +179,12 @@ protected virtual InternalVectorStoreFileContentResponse PersistableModelCreateC } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalVectorStoreFileContentResponse(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalVectorStoreFileContentResponse(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } diff --git a/src/Generated/Models/VectorStores/InternalVectorStoreSearchResultsPage.Serialization.cs b/src/Generated/Models/VectorStores/InternalVectorStoreSearchResultsPage.Serialization.cs index cab34a719..0f4363bcb 100644 --- a/src/Generated/Models/VectorStores/InternalVectorStoreSearchResultsPage.Serialization.cs +++ b/src/Generated/Models/VectorStores/InternalVectorStoreSearchResultsPage.Serialization.cs @@ -3,6 +3,7 @@ #nullable disable using System; +using System.ClientModel; using System.ClientModel.Primitives; using System.Collections.Generic; using System.Text.Json; @@ -217,5 +218,12 @@ protected virtual InternalVectorStoreSearchResultsPage PersistableModelCreateCor } string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public static explicit operator InternalVectorStoreSearchResultsPage(ClientResult result) + { + using PipelineResponse response = result.GetRawResponse(); + using JsonDocument document = JsonDocument.Parse(response.Content); + return DeserializeInternalVectorStoreSearchResultsPage(document.RootElement, ModelSerializationExtensions.WireOptions); + } } } From 38037d66a4650b687e8590109f0abed85deaf4a7 Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Mon, 21 Jul 2025 11:56:46 -0500 Subject: [PATCH 02/11] wip with options --- .../src/Visitors/PaginationVisitor.cs | 63 +++++++++ specification/client/models/chat.models.tsp | 34 +++++ specification/client/models/common.models.tsp | 21 +++ specification/main.tsp | 1 + src/Custom/Chat/Internal/GeneratorStubs.cs | 4 +- src/Generated/ChatClient.cs | 5 +- ...mpletionCollectionOptions.Serialization.cs | 123 ++++++++++++++++++ .../Chat/ChatCompletionCollectionOptions.cs | 46 +++++++ .../Chat/ChatCompletionCollectionOrder.cs | 44 +++++++ 9 files changed, 337 insertions(+), 4 deletions(-) create mode 100644 specification/client/models/chat.models.tsp create mode 100644 src/Generated/Models/Chat/ChatCompletionCollectionOptions.Serialization.cs create mode 100644 src/Generated/Models/Chat/ChatCompletionCollectionOptions.cs create mode 100644 src/Generated/Models/Chat/ChatCompletionCollectionOrder.cs diff --git a/codegen/generator/src/Visitors/PaginationVisitor.cs b/codegen/generator/src/Visitors/PaginationVisitor.cs index 070043845..f59879a2e 100644 --- a/codegen/generator/src/Visitors/PaginationVisitor.cs +++ b/codegen/generator/src/Visitors/PaginationVisitor.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -9,6 +10,7 @@ using Microsoft.TypeSpec.Generator.Providers; using Microsoft.TypeSpec.Generator.Snippets; using Microsoft.TypeSpec.Generator.Statements; +using NuGet.Packaging.Signing; using static OpenAILibraryPlugin.Visitors.VisitorHelpers; namespace OpenAILibraryPlugin.Visitors; @@ -18,8 +20,69 @@ namespace OpenAILibraryPlugin.Visitors; /// public class PaginationVisitor : ScmLibraryVisitor { + + static readonly string[] _chatParamsToReplace = ["after", "before", "limit", "order", "model", "metadata"]; + + private static readonly Dictionary _optionsReplacements = new() + { + { + "GetChatCompletions", + ("ChatCompletion", "ChatCompletionCollectionOptions", _chatParamsToReplace) + }, + { + "GetChatCompletionsAsync", + ("ChatCompletion", "ChatCompletionCollectionOptions", _chatParamsToReplace) + } + }; + protected override MethodProvider? VisitMethod(MethodProvider method) { + if (method.Signature.ReturnType is not null && + method.Signature.ReturnType.Name.EndsWith("CollectionResult") && + _optionsReplacements.TryGetValue(method.Signature.Name, out var options) && + method.Signature.ReturnType.IsGenericType && + method.Signature.ReturnType.Arguments.Count == 1 && + method.Signature.ReturnType.Arguments[0].Name == options.ReturnType) + { + var optionsType = OpenAILibraryGenerator.Instance.OutputLibrary.TypeProviders.SingleOrDefault(t => t.Type.Name == options.ReturnType); + if (optionsType is not null) + { + // replace the method parameters with names in the _paramsToReplace array with the optionsType + var methodSignature = method.Signature; + var newParameters = methodSignature.Parameters.ToList(); + int lastRemovedIndex = -1; + for (int i = 0; i < newParameters.Count; i++) + { + if (_chatParamsToReplace.Contains(newParameters[i].Name)) + { + newParameters.RemoveAt(i); + lastRemovedIndex = i; + i--; + } + } + if (lastRemovedIndex >= 0) + { + newParameters.Insert( + lastRemovedIndex, + new ParameterProvider("options", $"The pagination options", optionsType.Type, defaultValue: new KeywordExpression("default", null))); + + var newSignature = new MethodSignature( + methodSignature.Name, + methodSignature.Description, + methodSignature.Modifiers, + methodSignature.ReturnType, + methodSignature.ReturnDescription, + newParameters, + methodSignature.Attributes, + methodSignature.GenericArguments, + methodSignature.GenericParameterConstraints, + methodSignature.ExplicitInterface, + methodSignature.NonDocumentComment); + + method.Update(signature: newSignature); + } + } + } if (method.Signature.Name == "GetRawPagesAsync" && method.EnclosingType.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Internal)) { var statements = method.BodyStatements?.ToList() ?? new List(); diff --git a/specification/client/models/chat.models.tsp b/specification/client/models/chat.models.tsp new file mode 100644 index 000000000..28d8b7184 --- /dev/null +++ b/specification/client/models/chat.models.tsp @@ -0,0 +1,34 @@ +import "../../base/typespec/chat/main.tsp"; +import "@azure-tools/typespec-client-generator-core"; + +using Azure.ClientGenerator.Core; +using TypeSpec.Http; + +namespace OpenAI; + + +alias ChatCompletionCollectionOrderQueryParameter = { + /** + * Sort order by the `created_at` timestamp of the objects. `asc` for ascending order and`desc` + * for descending order. + */ + @query order?: ChatCompletionCollectionOrder; +}; + +union ChatCompletionCollectionOrder { + string, + Asc: "asc", + Desc: "desc", +} + +@access(Access.public) +@usage(Usage.input) +model ChatCompletionCollectionOptions { + ...CollectionAfterQueryParameter, + ...CollectionLimitQueryParameter, + ...ChatCompletionCollectionOrderQueryParameter, + @query metadata?: Record, + @query `model`?: string, +} + + diff --git a/specification/client/models/common.models.tsp b/specification/client/models/common.models.tsp index 2ea91f3da..7d3a74992 100644 --- a/specification/client/models/common.models.tsp +++ b/specification/client/models/common.models.tsp @@ -1,7 +1,9 @@ import "../../base/typespec/common/main.tsp"; import "@azure-tools/typespec-client-generator-core"; +import "@typespec/http"; using Azure.ClientGenerator.Core; +using TypeSpec.Http; namespace OpenAI; @@ -124,3 +126,22 @@ union DotNetChatVoiceIds { union DotNetRealtimeVoiceIds { VoiceIdsShared, } + +// CollectionQueryParameters + +alias CollectionLimitQueryParameter = { + /** + * A limit on the number of objects to be returned. Limit can range between 1 and 100, and the + * default is 20. + */ + @query pageSizeLimit?: int32 = 20; +}; + +alias CollectionAfterQueryParameter = { + /** + * A cursor for use in pagination. `after` is an object ID that defines your place in the list. + * For instance, if you make a list request and receive 100 objects, ending with obj_foo, your + * subsequent call can include after=obj_foo in order to fetch the next page of the list. + */ + @query @continuationToken afterId?: string; +}; \ No newline at end of file diff --git a/specification/main.tsp b/specification/main.tsp index db5d7d3b9..290078d10 100644 --- a/specification/main.tsp +++ b/specification/main.tsp @@ -16,5 +16,6 @@ import "./client/models/audio.models.tsp"; import "./client/models/common.models.tsp"; import "./client/models/responses.models.tsp"; import "./client/models/vector-stores.models.tsp"; +import "./client/models/chat.models.tsp"; import "./base/entrypoints/sdk.dotnet"; diff --git a/src/Custom/Chat/Internal/GeneratorStubs.cs b/src/Custom/Chat/Internal/GeneratorStubs.cs index 9e5acc63e..ff6269383 100644 --- a/src/Custom/Chat/Internal/GeneratorStubs.cs +++ b/src/Custom/Chat/Internal/GeneratorStubs.cs @@ -120,4 +120,6 @@ internal partial class InternalUnknownChatCompletionRequestMessageContentPart { [CodeGenType("ChatCompletionDeletedObject")] internal readonly partial struct InternalChatCompletionDeletedObject {} [CodeGenType("ChatCompletionMessageListObject")] internal readonly partial struct InternalChatCompletionMessageListObject {} [CodeGenType("ChatCompletionList")] internal partial class InternalChatCompletionList {} -[CodeGenType("ChatCompletionMessageList")] internal partial class InternalChatCompletionMessageList {} \ No newline at end of file +[CodeGenType("ChatCompletionMessageList")] internal partial class InternalChatCompletionMessageList {} +[CodeGenType("ChatCompletionCollectionOptions")] internal partial class ChatCompletionCollectionOptions {} +[CodeGenType("ChatCompletionCollectionOrder")] internal readonly partial struct ChatCompletionCollectionOrder { } \ No newline at end of file diff --git a/src/Generated/ChatClient.cs b/src/Generated/ChatClient.cs index faf7c4572..65c00d3bd 100644 --- a/src/Generated/ChatClient.cs +++ b/src/Generated/ChatClient.cs @@ -10,7 +10,6 @@ using System.Threading; using System.Threading.Tasks; using OpenAI; -using OpenAI.VectorStores; namespace OpenAI.Chat { @@ -51,7 +50,7 @@ public virtual AsyncCollectionResult GetChatCompletionsAsync(string after, int? } [Experimental("OPENAI001")] - public virtual CollectionResult GetChatCompletions(string after = default, int? limit = default, VectorStoreCollectionOrder? order = default, IDictionary metadata = default, string model = default, CancellationToken cancellationToken = default) + public virtual CollectionResult GetChatCompletions(ChatCompletion options = default, CancellationToken cancellationToken = default) { return new ChatClientGetChatCompletionsCollectionResultOfT( this, @@ -64,7 +63,7 @@ public virtual CollectionResult GetChatCompletions(string after } [Experimental("OPENAI001")] - public virtual AsyncCollectionResult GetChatCompletionsAsync(string after = default, int? limit = default, VectorStoreCollectionOrder? order = default, IDictionary metadata = default, string model = default, CancellationToken cancellationToken = default) + public virtual AsyncCollectionResult GetChatCompletionsAsync(ChatCompletion options = default, CancellationToken cancellationToken = default) { return new ChatClientGetChatCompletionsAsyncCollectionResultOfT( this, diff --git a/src/Generated/Models/Chat/ChatCompletionCollectionOptions.Serialization.cs b/src/Generated/Models/Chat/ChatCompletionCollectionOptions.Serialization.cs new file mode 100644 index 000000000..eff656623 --- /dev/null +++ b/src/Generated/Models/Chat/ChatCompletionCollectionOptions.Serialization.cs @@ -0,0 +1,123 @@ +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Text.Json; +using OpenAI; + +namespace OpenAI.Chat +{ + internal partial class ChatCompletionCollectionOptions : IJsonModel + { + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + writer.WriteStartObject(); + JsonModelWriteCore(writer, options); + writer.WriteEndObject(); + } + + protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(ChatCompletionCollectionOptions)} does not support writing '{format}' format."); + } + // Plugin customization: remove options.Format != "W" check + if (_additionalBinaryDataProperties != null) + { + foreach (var item in _additionalBinaryDataProperties) + { + if (ModelSerializationExtensions.IsSentinelValue(item.Value)) + { + continue; + } + writer.WritePropertyName(item.Key); +#if NET6_0_OR_GREATER + writer.WriteRawValue(item.Value); +#else + using (JsonDocument document = JsonDocument.Parse(item.Value)) + { + JsonSerializer.Serialize(writer, document.RootElement); + } +#endif + } + } + } + + ChatCompletionCollectionOptions IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) => JsonModelCreateCore(ref reader, options); + + protected virtual ChatCompletionCollectionOptions JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(ChatCompletionCollectionOptions)} does not support reading '{format}' format."); + } + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeChatCompletionCollectionOptions(document.RootElement, options); + } + + internal static ChatCompletionCollectionOptions DeserializeChatCompletionCollectionOptions(JsonElement element, ModelReaderWriterOptions options) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + string afterId = default; + int? pageSizeLimit = default; + ChatCompletionCollectionOrder? order = default; + IDictionary metadata = default; + string model = default; + IDictionary additionalBinaryDataProperties = new ChangeTrackingDictionary(); + foreach (var prop in element.EnumerateObject()) + { + // Plugin customization: remove options.Format != "W" check + additionalBinaryDataProperties.Add(prop.Name, BinaryData.FromString(prop.Value.GetRawText())); + } + return new ChatCompletionCollectionOptions( + afterId, + pageSizeLimit, + order, + metadata ?? new ChangeTrackingDictionary(), + model, + additionalBinaryDataProperties); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) => PersistableModelWriteCore(options); + + protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options, OpenAIContext.Default); + default: + throw new FormatException($"The model {nameof(ChatCompletionCollectionOptions)} does not support writing '{options.Format}' format."); + } + } + + ChatCompletionCollectionOptions IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) => PersistableModelCreateCore(data, options); + + protected virtual ChatCompletionCollectionOptions PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options) + { + string format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + switch (format) + { + case "J": + using (JsonDocument document = JsonDocument.Parse(data)) + { + return DeserializeChatCompletionCollectionOptions(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(ChatCompletionCollectionOptions)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + } +} diff --git a/src/Generated/Models/Chat/ChatCompletionCollectionOptions.cs b/src/Generated/Models/Chat/ChatCompletionCollectionOptions.cs new file mode 100644 index 000000000..586c93c13 --- /dev/null +++ b/src/Generated/Models/Chat/ChatCompletionCollectionOptions.cs @@ -0,0 +1,46 @@ +// + +#nullable disable + +using System; +using System.Collections.Generic; +using OpenAI; + +namespace OpenAI.Chat +{ + internal partial class ChatCompletionCollectionOptions + { + private protected IDictionary _additionalBinaryDataProperties; + + public ChatCompletionCollectionOptions() : this(null, default, default, null, null, null) + { + } + + internal ChatCompletionCollectionOptions(string afterId, int? pageSizeLimit, ChatCompletionCollectionOrder? order, IDictionary metadata, string model, IDictionary additionalBinaryDataProperties) + { + // Plugin customization: ensure initialization of collections + AfterId = afterId; + PageSizeLimit = pageSizeLimit; + Order = order; + Metadata = metadata ?? new ChangeTrackingDictionary(); + Model = model; + _additionalBinaryDataProperties = additionalBinaryDataProperties; + } + + public string AfterId { get; set; } + + public int? PageSizeLimit { get; set; } + + internal ChatCompletionCollectionOrder? Order { get; set; } + + public IDictionary Metadata { get; } + + public string Model { get; set; } + + internal IDictionary SerializedAdditionalRawData + { + get => _additionalBinaryDataProperties; + set => _additionalBinaryDataProperties = value; + } + } +} diff --git a/src/Generated/Models/Chat/ChatCompletionCollectionOrder.cs b/src/Generated/Models/Chat/ChatCompletionCollectionOrder.cs new file mode 100644 index 000000000..86183e7fc --- /dev/null +++ b/src/Generated/Models/Chat/ChatCompletionCollectionOrder.cs @@ -0,0 +1,44 @@ +// + +#nullable disable + +using System; +using System.ComponentModel; +using OpenAI; + +namespace OpenAI.Chat +{ + internal readonly partial struct ChatCompletionCollectionOrder : IEquatable + { + private readonly string _value; + private const string AscValue = "asc"; + private const string DescValue = "desc"; + + public ChatCompletionCollectionOrder(string value) + { + Argument.AssertNotNull(value, nameof(value)); + + _value = value; + } + + internal static ChatCompletionCollectionOrder Asc { get; } = new ChatCompletionCollectionOrder(AscValue); + + internal static ChatCompletionCollectionOrder Desc { get; } = new ChatCompletionCollectionOrder(DescValue); + + public static bool operator ==(ChatCompletionCollectionOrder left, ChatCompletionCollectionOrder right) => left.Equals(right); + + public static bool operator !=(ChatCompletionCollectionOrder left, ChatCompletionCollectionOrder right) => !left.Equals(right); + + public static implicit operator ChatCompletionCollectionOrder(string value) => new ChatCompletionCollectionOrder(value); + + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => obj is ChatCompletionCollectionOrder other && Equals(other); + + public bool Equals(ChatCompletionCollectionOrder other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); + + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => _value != null ? StringComparer.InvariantCultureIgnoreCase.GetHashCode(_value) : 0; + + public override string ToString() => _value; + } +} From 2786c952e1cbfa42ed2908700604483f391d2652 Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Mon, 21 Jul 2025 12:01:41 -0500 Subject: [PATCH 03/11] comments --- codegen/generator/src/Visitors/PaginationVisitor.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/codegen/generator/src/Visitors/PaginationVisitor.cs b/codegen/generator/src/Visitors/PaginationVisitor.cs index f59879a2e..3ed9cdf75 100644 --- a/codegen/generator/src/Visitors/PaginationVisitor.cs +++ b/codegen/generator/src/Visitors/PaginationVisitor.cs @@ -1,27 +1,24 @@ using System; using System.Collections.Generic; using System.Linq; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.TypeSpec.Generator.ClientModel; -using Microsoft.TypeSpec.Generator.ClientModel.Providers; using Microsoft.TypeSpec.Generator.Expressions; -using Microsoft.TypeSpec.Generator.Input; using Microsoft.TypeSpec.Generator.Primitives; using Microsoft.TypeSpec.Generator.Providers; using Microsoft.TypeSpec.Generator.Snippets; using Microsoft.TypeSpec.Generator.Statements; -using NuGet.Packaging.Signing; using static OpenAILibraryPlugin.Visitors.VisitorHelpers; namespace OpenAILibraryPlugin.Visitors; /// /// This visitor modifies GetRawPagesAsync methods to consider HasMore in addition to LastId when deciding whether to continue pagination. +/// It also replaces specific parameters with an options type for pagination methods. /// public class PaginationVisitor : ScmLibraryVisitor { - static readonly string[] _chatParamsToReplace = ["after", "before", "limit", "order", "model", "metadata"]; + private static readonly string[] _chatParamsToReplace = ["after", "before", "limit", "order", "model", "metadata"]; private static readonly Dictionary _optionsReplacements = new() { @@ -37,6 +34,8 @@ public class PaginationVisitor : ScmLibraryVisitor protected override MethodProvider? VisitMethod(MethodProvider method) { + // Check if the method is one of the pagination methods we want to modify. + // If so, we will update its parameters to replace the specified parameters with the options type. if (method.Signature.ReturnType is not null && method.Signature.ReturnType.Name.EndsWith("CollectionResult") && _optionsReplacements.TryGetValue(method.Signature.Name, out var options) && @@ -83,6 +82,9 @@ public class PaginationVisitor : ScmLibraryVisitor } } } + + // If the method is GetRawPagesAsync and is internal, we will modify the body statements to add a check for hasMore == false. + // This is to ensure that pagination stops when hasMore is false, in addition to checking LastId. if (method.Signature.Name == "GetRawPagesAsync" && method.EnclosingType.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Internal)) { var statements = method.BodyStatements?.ToList() ?? new List(); From 7970bdf73da3facb5e6edeb72a893a08eee64d24 Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Mon, 21 Jul 2025 17:55:51 -0500 Subject: [PATCH 04/11] fixup params --- .../src/Visitors/PaginationVisitor.cs | 78 ++++++++++++++++++- src/Custom/Chat/Internal/GeneratorStubs.cs | 4 +- src/Generated/ChatClient.cs | 24 +++--- ...mpletionCollectionOptions.Serialization.cs | 2 +- .../Chat/ChatCompletionCollectionOptions.cs | 6 +- .../Chat/ChatCompletionCollectionOrder.cs | 8 +- src/Generated/OpenAIModelFactory.cs | 13 ++++ 7 files changed, 111 insertions(+), 24 deletions(-) diff --git a/codegen/generator/src/Visitors/PaginationVisitor.cs b/codegen/generator/src/Visitors/PaginationVisitor.cs index 3ed9cdf75..eac395d7e 100644 --- a/codegen/generator/src/Visitors/PaginationVisitor.cs +++ b/codegen/generator/src/Visitors/PaginationVisitor.cs @@ -19,7 +19,15 @@ public class PaginationVisitor : ScmLibraryVisitor { private static readonly string[] _chatParamsToReplace = ["after", "before", "limit", "order", "model", "metadata"]; - + private static readonly Dictionary _paramReplacementMap = new() + { + { "after", "AfterId" }, + { "before", "LastId" }, + { "limit", "PageSizeLimit" }, + { "order", "Order" }, + { "model", "Model" }, + { "metadata", "Metadata" } + }; private static readonly Dictionary _optionsReplacements = new() { { @@ -36,14 +44,15 @@ public class PaginationVisitor : ScmLibraryVisitor { // Check if the method is one of the pagination methods we want to modify. // If so, we will update its parameters to replace the specified parameters with the options type. - if (method.Signature.ReturnType is not null && + if ( + method.Signature.ReturnType is not null && method.Signature.ReturnType.Name.EndsWith("CollectionResult") && _optionsReplacements.TryGetValue(method.Signature.Name, out var options) && method.Signature.ReturnType.IsGenericType && method.Signature.ReturnType.Arguments.Count == 1 && method.Signature.ReturnType.Arguments[0].Name == options.ReturnType) { - var optionsType = OpenAILibraryGenerator.Instance.OutputLibrary.TypeProviders.SingleOrDefault(t => t.Type.Name == options.ReturnType); + var optionsType = OpenAILibraryGenerator.Instance.OutputLibrary.TypeProviders.SingleOrDefault(t => t.Type.Name == options.OptionsType); if (optionsType is not null) { // replace the method parameters with names in the _paramsToReplace array with the optionsType @@ -78,7 +87,68 @@ public class PaginationVisitor : ScmLibraryVisitor methodSignature.ExplicitInterface, methodSignature.NonDocumentComment); - method.Update(signature: newSignature); + var optionsParam = newParameters[lastRemovedIndex]; + + // Update the method body statements to replace the old parameters with the new options parameter. + var statements = method.BodyStatements?.ToList() ?? new List(); + VisitExplodedMethodBodyStatements(statements!, + statement => + { + // Check if the statement is a return statement + if (statement is ExpressionStatement exp && exp.Expression is KeywordExpression keyword && keyword.Keyword == "return") + { + // If it is, we will replace the parameters with the options parameter. + if (keyword.Expression is NewInstanceExpression newInstance && + newInstance.Parameters.Count > 0) + { + // Create the new parameters with the options parameter. + var newParameters = new List(); + foreach (var param in newInstance.Parameters) + { + if (param is VariableExpression varExpr && options.ParamsToReplace.Contains(varExpr.Declaration.RequestedName)) + { + // Replace the parameter with the options parameter. + if (_paramReplacementMap.TryGetValue(varExpr.Declaration.RequestedName, out var replacement)) + { + newParameters.Add(optionsParam.NullConditional().Property(replacement)); + var foo = optionsParam.NullConditional().Property(replacement).NullConditional().Invoke("ToString", Array.Empty()); + } + } + else if (param is InvokeMethodExpression invokeMethod && invokeMethod.MethodName == "ToString" && + invokeMethod.InstanceReference is NullConditionalExpression nullConditional && + nullConditional.Inner is VariableExpression varExpr2 && + options.ParamsToReplace.Contains(varExpr2.Declaration.RequestedName)) + { + // Replace the parameter with the options parameter. + if (_paramReplacementMap.TryGetValue(varExpr2.Declaration.RequestedName, out var replacement)) + { + newParameters.Add(optionsParam.NullConditional().Property(replacement).NullConditional().Invoke("ToString", Array.Empty())); + } + } + else + { + // Keep the original parameter. + newParameters.Add(param); + } + } + // Create a new ExpressionStatement with the same children as the original, but with the new parameters. + var newNewInstanceExpression = new NewInstanceExpression( + newInstance.Type, + newParameters); + + var newKeywordExpression = new KeywordExpression( + keyword.Keyword, + newNewInstanceExpression); + + var newExpressionStatement = new ExpressionStatement(newKeywordExpression); + + return newExpressionStatement; + } + } + return statement; + }); + + method.Update(signature: newSignature, bodyStatements: statements); } } } diff --git a/src/Custom/Chat/Internal/GeneratorStubs.cs b/src/Custom/Chat/Internal/GeneratorStubs.cs index ff6269383..bcdb80c9c 100644 --- a/src/Custom/Chat/Internal/GeneratorStubs.cs +++ b/src/Custom/Chat/Internal/GeneratorStubs.cs @@ -121,5 +121,5 @@ internal partial class InternalUnknownChatCompletionRequestMessageContentPart { [CodeGenType("ChatCompletionMessageListObject")] internal readonly partial struct InternalChatCompletionMessageListObject {} [CodeGenType("ChatCompletionList")] internal partial class InternalChatCompletionList {} [CodeGenType("ChatCompletionMessageList")] internal partial class InternalChatCompletionMessageList {} -[CodeGenType("ChatCompletionCollectionOptions")] internal partial class ChatCompletionCollectionOptions {} -[CodeGenType("ChatCompletionCollectionOrder")] internal readonly partial struct ChatCompletionCollectionOrder { } \ No newline at end of file +[CodeGenType("ChatCompletionCollectionOptions")] public partial class ChatCompletionCollectionOptions {} +[CodeGenType("ChatCompletionCollectionOrder")] public readonly partial struct ChatCompletionCollectionOrder { } \ No newline at end of file diff --git a/src/Generated/ChatClient.cs b/src/Generated/ChatClient.cs index 65c00d3bd..7dcf1b723 100644 --- a/src/Generated/ChatClient.cs +++ b/src/Generated/ChatClient.cs @@ -50,28 +50,28 @@ public virtual AsyncCollectionResult GetChatCompletionsAsync(string after, int? } [Experimental("OPENAI001")] - public virtual CollectionResult GetChatCompletions(ChatCompletion options = default, CancellationToken cancellationToken = default) + public virtual CollectionResult GetChatCompletions(ChatCompletionCollectionOptions options = default, CancellationToken cancellationToken = default) { return new ChatClientGetChatCompletionsCollectionResultOfT( this, - after, - limit, - order?.ToString(), - metadata, - model, + options?.AfterId, + options?.PageSizeLimit, + options?.Order?.ToString(), + options?.Metadata, + options?.Model, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null); } [Experimental("OPENAI001")] - public virtual AsyncCollectionResult GetChatCompletionsAsync(ChatCompletion options = default, CancellationToken cancellationToken = default) + public virtual AsyncCollectionResult GetChatCompletionsAsync(ChatCompletionCollectionOptions options = default, CancellationToken cancellationToken = default) { return new ChatClientGetChatCompletionsAsyncCollectionResultOfT( this, - after, - limit, - order?.ToString(), - metadata, - model, + options?.AfterId, + options?.PageSizeLimit, + options?.Order?.ToString(), + options?.Metadata, + options?.Model, cancellationToken.CanBeCanceled ? new RequestOptions { CancellationToken = cancellationToken } : null); } diff --git a/src/Generated/Models/Chat/ChatCompletionCollectionOptions.Serialization.cs b/src/Generated/Models/Chat/ChatCompletionCollectionOptions.Serialization.cs index eff656623..44c2b99ba 100644 --- a/src/Generated/Models/Chat/ChatCompletionCollectionOptions.Serialization.cs +++ b/src/Generated/Models/Chat/ChatCompletionCollectionOptions.Serialization.cs @@ -10,7 +10,7 @@ namespace OpenAI.Chat { - internal partial class ChatCompletionCollectionOptions : IJsonModel + public partial class ChatCompletionCollectionOptions : IJsonModel { void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) { diff --git a/src/Generated/Models/Chat/ChatCompletionCollectionOptions.cs b/src/Generated/Models/Chat/ChatCompletionCollectionOptions.cs index 586c93c13..8b5aaa219 100644 --- a/src/Generated/Models/Chat/ChatCompletionCollectionOptions.cs +++ b/src/Generated/Models/Chat/ChatCompletionCollectionOptions.cs @@ -4,11 +4,13 @@ using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using OpenAI; namespace OpenAI.Chat { - internal partial class ChatCompletionCollectionOptions + [Experimental("OPENAI001")] + public partial class ChatCompletionCollectionOptions { private protected IDictionary _additionalBinaryDataProperties; @@ -31,7 +33,7 @@ internal ChatCompletionCollectionOptions(string afterId, int? pageSizeLimit, Cha public int? PageSizeLimit { get; set; } - internal ChatCompletionCollectionOrder? Order { get; set; } + public ChatCompletionCollectionOrder? Order { get; set; } public IDictionary Metadata { get; } diff --git a/src/Generated/Models/Chat/ChatCompletionCollectionOrder.cs b/src/Generated/Models/Chat/ChatCompletionCollectionOrder.cs index 86183e7fc..bac255c46 100644 --- a/src/Generated/Models/Chat/ChatCompletionCollectionOrder.cs +++ b/src/Generated/Models/Chat/ChatCompletionCollectionOrder.cs @@ -4,11 +4,13 @@ using System; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using OpenAI; namespace OpenAI.Chat { - internal readonly partial struct ChatCompletionCollectionOrder : IEquatable + [Experimental("OPENAI001")] + public readonly partial struct ChatCompletionCollectionOrder : IEquatable { private readonly string _value; private const string AscValue = "asc"; @@ -21,9 +23,9 @@ public ChatCompletionCollectionOrder(string value) _value = value; } - internal static ChatCompletionCollectionOrder Asc { get; } = new ChatCompletionCollectionOrder(AscValue); + public static ChatCompletionCollectionOrder Asc { get; } = new ChatCompletionCollectionOrder(AscValue); - internal static ChatCompletionCollectionOrder Desc { get; } = new ChatCompletionCollectionOrder(DescValue); + public static ChatCompletionCollectionOrder Desc { get; } = new ChatCompletionCollectionOrder(DescValue); public static bool operator ==(ChatCompletionCollectionOrder left, ChatCompletionCollectionOrder right) => left.Equals(right); diff --git a/src/Generated/OpenAIModelFactory.cs b/src/Generated/OpenAIModelFactory.cs index a0e21804c..e76effbf4 100644 --- a/src/Generated/OpenAIModelFactory.cs +++ b/src/Generated/OpenAIModelFactory.cs @@ -1035,5 +1035,18 @@ public static AudioTokenLogProbabilityDetails AudioTokenLogProbabilityDetails(st { return new AudioTokenLogProbabilityDetails(token, logProbability, utf8Bytes, additionalBinaryDataProperties: null); } + + public static ChatCompletionCollectionOptions ChatCompletionCollectionOptions(string afterId = default, int? pageSizeLimit = default, ChatCompletionCollectionOrder? order = default, IDictionary metadata = default, string model = default) + { + metadata ??= new ChangeTrackingDictionary(); + + return new ChatCompletionCollectionOptions( + afterId, + pageSizeLimit, + order, + metadata, + model, + additionalBinaryDataProperties: null); + } } } From 797750719618f711e52cfeeeb53111cbf34672bb Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Tue, 22 Jul 2025 18:29:10 -0500 Subject: [PATCH 05/11] fixup metadata query param --- .../generator/src/OpenAILibraryGenerator.cs | 1 + .../src/Visitors/MetadataQueryParamVisitor.cs | 130 +++++ .../src/Visitors/PaginationVisitor.cs | 42 +- .../generator/src/Visitors/VisitorHelpers.cs | 14 +- src/Generated/ChatClient.RestClient.cs | 8 +- tests/Chat/ChatTests.cs | 530 ++++++++++++++++++ 6 files changed, 714 insertions(+), 11 deletions(-) create mode 100644 codegen/generator/src/Visitors/MetadataQueryParamVisitor.cs diff --git a/codegen/generator/src/OpenAILibraryGenerator.cs b/codegen/generator/src/OpenAILibraryGenerator.cs index 30951a4e2..5f33fc4e1 100644 --- a/codegen/generator/src/OpenAILibraryGenerator.cs +++ b/codegen/generator/src/OpenAILibraryGenerator.cs @@ -39,6 +39,7 @@ protected override void Configure() AddVisitor(new ExperimentalAttributeVisitor()); AddVisitor(new ModelDirectoryVisitor()); AddVisitor(new PaginationVisitor()); + AddVisitor(new MetadataQueryParamVisitor()); } } } \ No newline at end of file diff --git a/codegen/generator/src/Visitors/MetadataQueryParamVisitor.cs b/codegen/generator/src/Visitors/MetadataQueryParamVisitor.cs new file mode 100644 index 000000000..626f939eb --- /dev/null +++ b/codegen/generator/src/Visitors/MetadataQueryParamVisitor.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.TypeSpec.Generator.ClientModel; +using Microsoft.TypeSpec.Generator.Expressions; +using Microsoft.TypeSpec.Generator.Primitives; +using Microsoft.TypeSpec.Generator.Providers; +using Microsoft.TypeSpec.Generator.Snippets; +using Microsoft.TypeSpec.Generator.Statements; +using static OpenAILibraryPlugin.Visitors.VisitorHelpers; + +namespace OpenAILibraryPlugin.Visitors; + +/// +/// This visitor modifies GetRawPagesAsync methods to consider HasMore in addition to LastId when deciding whether to continue pagination. +/// It also replaces specific parameters with an options type for pagination methods. +/// +public class MetadataQueryParamVisitor : ScmLibraryVisitor +{ + + private static readonly string[] _chatParamsToReplace = ["after", "before", "limit", "order", "model", "metadata"]; + private static readonly Dictionary _paramReplacementMap = new() + { + { "after", "AfterId" }, + { "before", "LastId" }, + { "limit", "PageSizeLimit" }, + { "order", "Order" }, + { "model", "Model" }, + { "metadata", "Metadata" } + }; + private static readonly Dictionary _optionsReplacements = new() + { + { + "GetChatCompletions", + ("ChatCompletion", "ChatCompletionCollectionOptions", _chatParamsToReplace) + }, + { + "GetChatCompletionsAsync", + ("ChatCompletion", "ChatCompletionCollectionOptions", _chatParamsToReplace) + } + }; + + /// + /// Visits Create*Request methods to modify how metadata query parameters are handled. + /// It replaces the following statements: + /// + /// List list = new List(); + /// foreach (var @param in metadata) + /// { + /// uri.AppendQuery($"metadata[{@param.Key}]", @param.Value, true); + /// list.Add(@param.Key); + /// list.Add(@param.Value); + /// } + /// uri.AppendQueryDelimited("metadata", list, ",", null, true); + /// + /// with: + /// + /// foreach (var @param in metadata) + /// { + /// uri.AppendQuery($"metadata[{@param.Key}]", @param.Value, true); + /// } + /// + /// + /// + protected override MethodProvider? VisitMethod(MethodProvider method) + { + // Check if the method is one of the Create*Request methods and has a signature that takes a metadata parameter like IDictionary metadata + if (method.Signature.Name.StartsWith("Create") && method.Signature.Name.EndsWith("Request") && + method.Signature.Parameters.Any(p => p.Type.IsDictionary && p.Name == "metadata")) + { + ValueExpression? uri = null; + var statements = method.BodyStatements?.ToList() ?? new List(); + VisitExplodedMethodBodyStatements( + statements!, + statement => + { + // Check if the statement is an assignment to a variable named "uri" + // Capture it if so + if (statement is ExpressionStatement expressionStatement && + expressionStatement.Expression is AssignmentExpression assignmentExpression && + assignmentExpression.Variable is DeclarationExpression declarationExpression && + declarationExpression.Variable is VariableExpression variableExpression && + variableExpression.Declaration.RequestedName == "uri") + { + uri = variableExpression; + } + // Try to remove the unnecessary list declaration + if (statement is ExpressionStatement expressionStatement2 && + expressionStatement2.Expression is AssignmentExpression assignmentExpression2 && + assignmentExpression2.Variable is DeclarationExpression declarationExpression2 && + declarationExpression2.Variable is VariableExpression variableExpression2 && + variableExpression2.Declaration.RequestedName == "list" && + variableExpression2.Type.IsCollection && variableExpression2.Type.IsGenericType) + { + // Remove the list declaration + return new SingleLineCommentStatement("Plugin customization: remove unnecessary list declaration"); + } + + if (uri is not null && + statement is ForEachStatement foreachStatement && + foreachStatement.Enumerable is DictionaryExpression dictionaryExpression && + dictionaryExpression.Original is VariableExpression variable && + variable.Declaration.RequestedName == "metadata") + { + var formatString = new FormattableStringExpression("metadata[{0}]", [foreachStatement.ItemVariable.Property("Key")]); + var appendQueryStatement = uri.Invoke("AppendQuery", [formatString, foreachStatement.ItemVariable.Property("Value"), new KeywordExpression("true", null)]); + foreachStatement.Body.Clear(); + foreachStatement.Body.Add(new SingleLineCommentStatement("Plugin customization: Properly handle metadata query parameters")); + foreachStatement.Body.Add(new ExpressionStatement(appendQueryStatement)); + } + + // Remove the call to AppendQueryDelimited for metadata + if (statement is ExpressionStatement expressionStatement3 && + expressionStatement3.Expression is InvokeMethodExpression invokeMethodExpression && + invokeMethodExpression.MethodName == "AppendQueryDelimited" && + invokeMethodExpression.Arguments.Count == 5 && + invokeMethodExpression.Arguments[0].ToDisplayString() == "\"metadata\"") + { + return new SingleLineCommentStatement("Plugin customization: remove unnecessary AppendQueryDelimited for metadata"); + } + return statement; + }); + + // Rebuild the method body with the modified statements + method.Update(bodyStatements: statements); + } + + return base.VisitMethod(method); + } +} \ No newline at end of file diff --git a/codegen/generator/src/Visitors/PaginationVisitor.cs b/codegen/generator/src/Visitors/PaginationVisitor.cs index eac395d7e..2c0ab10a9 100644 --- a/codegen/generator/src/Visitors/PaginationVisitor.cs +++ b/codegen/generator/src/Visitors/PaginationVisitor.cs @@ -41,11 +41,32 @@ public class PaginationVisitor : ScmLibraryVisitor }; protected override MethodProvider? VisitMethod(MethodProvider method) + { + // Try to handle pagination methods with options replacement + if (TryHandlePaginationMethodWithOptions(method)) + { + return method; + } + + // Try to handle GetRawPagesAsync methods for hasMore checks + if (TryHandleGetRawPagesAsyncMethod(method)) + { + return method; + } + + return base.VisitMethod(method); + } + + /// + /// Handles pagination methods that need their parameters replaced with an options type. + /// + /// The method to potentially handle. Will be modified in place if handling is successful. + /// True if the method was handled, false otherwise. + private bool TryHandlePaginationMethodWithOptions(MethodProvider method) { // Check if the method is one of the pagination methods we want to modify. // If so, we will update its parameters to replace the specified parameters with the options type. - if ( - method.Signature.ReturnType is not null && + if (method.Signature.ReturnType is not null && method.Signature.ReturnType.Name.EndsWith("CollectionResult") && _optionsReplacements.TryGetValue(method.Signature.Name, out var options) && method.Signature.ReturnType.IsGenericType && @@ -111,7 +132,6 @@ method.Signature.ReturnType is not null && if (_paramReplacementMap.TryGetValue(varExpr.Declaration.RequestedName, out var replacement)) { newParameters.Add(optionsParam.NullConditional().Property(replacement)); - var foo = optionsParam.NullConditional().Property(replacement).NullConditional().Invoke("ToString", Array.Empty()); } } else if (param is InvokeMethodExpression invokeMethod && invokeMethod.MethodName == "ToString" && @@ -149,10 +169,21 @@ nullConditional.Inner is VariableExpression varExpr2 && }); method.Update(signature: newSignature, bodyStatements: statements); + return true; } } } + return false; + } + + /// + /// Handles GetRawPagesAsync methods to add hasMore == false checks for pagination. + /// + /// The method to potentially handle. Will be modified in place if handling is successful. + /// True if the method was handled, false otherwise. + private bool TryHandleGetRawPagesAsyncMethod(MethodProvider method) + { // If the method is GetRawPagesAsync and is internal, we will modify the body statements to add a check for hasMore == false. // This is to ensure that pagination stops when hasMore is false, in addition to checking LastId. if (method.Signature.Name == "GetRawPagesAsync" && method.EnclosingType.DeclarationModifiers.HasFlag(TypeSignatureModifiers.Internal)) @@ -197,6 +228,7 @@ binaryExpr.Right is KeywordExpression rightKeyword && .SelectMany(bodyStatement => bodyStatement) .ToList(); + // Check for the assignment of nextToken and add hasMore assignment for (int i = 0; i < statementList.Count; i++) { if (statementList[i] is ExpressionStatement expressionStatement && @@ -227,9 +259,9 @@ assignmentExpression.Value is MemberExpression memberExpression && }); method.Update(bodyStatements: statements); - return method; + return true; } - return base.VisitMethod(method); + return false; } } \ No newline at end of file diff --git a/codegen/generator/src/Visitors/VisitorHelpers.cs b/codegen/generator/src/Visitors/VisitorHelpers.cs index c1c5bcee0..37b7dedae 100644 --- a/codegen/generator/src/Visitors/VisitorHelpers.cs +++ b/codegen/generator/src/Visitors/VisitorHelpers.cs @@ -16,7 +16,7 @@ internal static void VisitExplodedMethodBodyStatements( for (int i = 0; i < statements.Count; i++) { statements[i] = visitorFunc.Invoke(statements[i]); - + if (statements[i] is ForEachStatement foreachStatement) { List foreachBodyStatements @@ -29,7 +29,17 @@ List foreachBodyStatements } else if (statements[i] is IfStatement ifStatement) { - // To do: traverse inside of "if" + List ifBodyStatements + = ifStatement.Body + .SelectMany(bodyStatement => bodyStatement) + .ToList(); + VisitExplodedMethodBodyStatements(ifBodyStatements!, visitorFunc); + var newIfStatement = new IfStatement(ifStatement.Condition); + foreach (MethodBodyStatement bodyStatement in ifBodyStatements) + { + newIfStatement.Add(bodyStatement); + } + statements[i] = newIfStatement; } else if (statements[i] is ForStatement forStatement) { diff --git a/src/Generated/ChatClient.RestClient.cs b/src/Generated/ChatClient.RestClient.cs index c62992313..898dda5a3 100644 --- a/src/Generated/ChatClient.RestClient.cs +++ b/src/Generated/ChatClient.RestClient.cs @@ -38,13 +38,13 @@ internal virtual PipelineMessage CreateGetChatCompletionsRequest(string after, i } if (metadata != null && !(metadata is ChangeTrackingDictionary changeTrackingDictionary && changeTrackingDictionary.IsUndefined)) { - List list = new List(); + // Plugin customization: remove unnecessary list declaration foreach (var @param in metadata) { - list.Add(@param.Key); - list.Add(@param.Value); + // Plugin customization: Properly handle metadata query parameters + uri.AppendQuery($"metadata[{@param.Key}]", @param.Value, true); } - uri.AppendQueryDelimited("metadata", list, ",", null, true); + // Plugin customization: remove unnecessary AppendQueryDelimited for metadata } if (model != null) { diff --git a/tests/Chat/ChatTests.cs b/tests/Chat/ChatTests.cs index a6a003a67..d4721e4e3 100644 --- a/tests/Chat/ChatTests.cs +++ b/tests/Chat/ChatTests.cs @@ -1042,6 +1042,13 @@ public async Task ChatMetadata() ChatCompletion completion = await client.CompleteChatAsync( ["Hello, world!"], options); + + int count = 0; + await foreach (var fetchedCompletion in client.GetChatCompletionsAsync()) + { + count++; + } + Assert.That(count, Is.GreaterThan(0)); } [Test] @@ -1061,6 +1068,392 @@ public async Task WebSearchWorks() Assert.That(completion.Annotations, Has.Count.GreaterThan(0)); } + [Test] + public async Task GetChatCompletionsWithPagination() + { + ChatClient client = GetTestClient(); + + // Create multiple completions with stored output enabled + var completionIds = new List(); + for (int i = 0; i < 3; i++) + { + ChatCompletionOptions options = new() + { + StoredOutputEnabled = true, + Metadata = { ["test_key"] = $"test_value_{i}" } + }; + + ChatCompletion completion = await client.CompleteChatAsync( + [$"Test message {i}: Say 'Hello World {i}'"], + options); + + completionIds.Add(completion.Id); + } + + Thread.Sleep(5000); // Wait for completions to be stored + + // Test pagination with limit + ChatCompletionCollectionOptions paginationOptions = new() + { + PageSizeLimit = 2 + }; + + int totalCount = 0; + string lastId = null; + + await foreach (var fetchedCompletion in client.GetChatCompletionsAsync(paginationOptions)) + { + totalCount++; + lastId = fetchedCompletion.Id; + Assert.That(fetchedCompletion.Id, Is.Not.Null.And.Not.Empty); + Assert.That(fetchedCompletion.Content, Is.Not.Null); + + if (totalCount >= 2) break; // Stop after getting 2 items + } + + Assert.That(totalCount, Is.EqualTo(2)); + Assert.That(lastId, Is.Not.Null); + + // Clean up + foreach (var id in completionIds) + { + try + { + await client.DeleteChatCompletionAsync(id); + } + catch { /* Ignore cleanup errors */ } + } + } + + [Test] + public async Task GetChatCompletionsWithAfterIdPagination() + { + ChatClient client = GetTestClient(); + + // Create multiple completions + var completionIds = new List(); + for (int i = 0; i < 3; i++) + { + ChatCompletionOptions createOptions = new() + { + StoredOutputEnabled = true + }; + + ChatCompletion completion = await client.CompleteChatAsync( + [$"Pagination test {i}: Say 'Test {i}'"], + createOptions); + + completionIds.Add(completion.Id); + } + + Thread.Sleep(5000); // Wait for completions to be stored + + // Get first completion to use as afterId + string afterId = null; + await foreach (var firstCompletion in client.GetChatCompletionsAsync()) + { + afterId = firstCompletion.Id; + break; + } + + Assert.That(afterId, Is.Not.Null); + + // Test pagination starting after the first ID + ChatCompletionCollectionOptions paginationOptions = new() + { + AfterId = afterId, + PageSizeLimit = 2 + }; + + int count = 0; + await foreach (var completion in client.GetChatCompletionsAsync(paginationOptions)) + { + count++; + // Ensure we don't get the afterId completion + Assert.That(completion.Id, Is.Not.EqualTo(afterId)); + if (count >= 2) break; + } + + // Clean up + foreach (var id in completionIds) + { + try + { + await client.DeleteChatCompletionAsync(id); + } + catch { /* Ignore cleanup errors */ } + } + } + + [Test] + public async Task GetChatCompletionsWithOrderFiltering() + { + ChatClient client = GetTestClient(); + + // Create completions with timestamps + var completionIds = new List(); + for (int i = 0; i < 2; i++) + { + ChatCompletionOptions createOptions = new() + { + StoredOutputEnabled = true, + Metadata = { ["sequence"] = i.ToString() } + }; + + ChatCompletion completion = await client.CompleteChatAsync( + [$"Order test {i}: Say 'Order {i}'"], + createOptions); + + completionIds.Add(completion.Id); + Thread.Sleep(1000); // Ensure different timestamps + } + + Thread.Sleep(5000); // Wait for completions to be stored + + // Test ascending order + ChatCompletionCollectionOptions ascOptions = new() + { + Order = ChatCompletionCollectionOrder.Asc, + PageSizeLimit = 5 + }; + + var ascResults = new List(); + await foreach (var completion in client.GetChatCompletionsAsync(ascOptions)) + { + ascResults.Add(completion); + if (ascResults.Count >= 2) break; + } + + // Test descending order + ChatCompletionCollectionOptions descOptions = new() + { + Order = ChatCompletionCollectionOrder.Desc, + PageSizeLimit = 5 + }; + + var descResults = new List(); + await foreach (var completion in client.GetChatCompletionsAsync(descOptions)) + { + descResults.Add(completion); + if (descResults.Count >= 2) break; + } + + // Verify we get results in both cases + Assert.That(ascResults, Has.Count.GreaterThan(0)); + Assert.That(descResults, Has.Count.GreaterThan(0)); + + // The first result in descending order should be the most recent + // (though exact ordering validation is tricky due to timing) + Assert.That(descResults[0].Id, Is.Not.Null.And.Not.Empty); + + // Clean up + foreach (var id in completionIds) + { + try + { + await client.DeleteChatCompletionAsync(id); + } + catch { /* Ignore cleanup errors */ } + } + } + + [Test] + public async Task GetChatCompletionsWithMetadataFiltering() + { + ChatClient client = GetTestClient(); + + // Create completions with different metadata + var testMetadataKey = $"test_scenario_{Guid.NewGuid():N}"; + var completionIds = new List(); + + // Create completion with specific metadata + ChatCompletionOptions options1 = new() + { + StoredOutputEnabled = true, + Metadata = { [testMetadataKey] = "target_value" } + }; + + ChatCompletion targetCompletion = await client.CompleteChatAsync( + ["Metadata test: Say 'Target completion'"], + options1); + completionIds.Add(targetCompletion.Id); + + // Create completion with different metadata + ChatCompletionOptions options2 = new() + { + StoredOutputEnabled = true, + Metadata = { [testMetadataKey] = "other_value" } + }; + + ChatCompletion otherCompletion = await client.CompleteChatAsync( + ["Metadata test: Say 'Other completion'"], + options2); + completionIds.Add(otherCompletion.Id); + + Thread.Sleep(5000); // Wait for completions to be stored + + // Filter by specific metadata + ChatCompletionCollectionOptions filterOptions = new() + { + Metadata = { [testMetadataKey] = "target_value" }, + PageSizeLimit = 10 + }; + + int totalFound = 0; + + await foreach (var completion in client.GetChatCompletionsAsync(filterOptions)) + { + totalFound++; + Assert.That(completion.Id, Is.Not.Null.And.Not.Empty); + if (totalFound >= 20) break; // Prevent infinite loop + } + + // Should find completions (filtering behavior may vary by implementation) + Assert.That(totalFound, Is.GreaterThan(0)); + + // Clean up + foreach (var id in completionIds) + { + try + { + await client.DeleteChatCompletionAsync(id); + } + catch { /* Ignore cleanup errors */ } + } + } + + [Test] + public async Task GetChatCompletionsWithModelFiltering() + { + ChatClient client = GetTestClient(); + + // Create completion with default model + ChatCompletionOptions createOptions = new() + { + StoredOutputEnabled = true, + Metadata = { ["model_test"] = "true" } + }; + + ChatCompletion completion = await client.CompleteChatAsync( + ["Model filter test: Say 'Hello'"], + createOptions); + + Thread.Sleep(5000); // Wait for completion to be stored + + // Filter by the model used by the test client + ChatCompletionCollectionOptions filterOptions = new() + { + Model = "gpt-4o-mini-2024-07-18", // Common test model + PageSizeLimit = 10 + }; + + int count = 0; + await foreach (var fetchedCompletion in client.GetChatCompletionsAsync(filterOptions)) + { + count++; + Assert.That(fetchedCompletion.Id, Is.Not.Null.And.Not.Empty); + // Note: The actual model filtering behavior depends on the service implementation + if (count >= 5) break; // Limit results for test performance + } + + Assert.That(count, Is.GreaterThan(0)); + + // Clean up + try + { + await client.DeleteChatCompletionAsync(completion.Id); + } + catch { /* Ignore cleanup errors */ } + } + + [Test] + public async Task GetChatCompletionsWithEmptyOptions() + { + ChatClient client = GetTestClient(); + + // Create a completion to ensure we have something to fetch + ChatCompletionOptions createOptions = new() + { + StoredOutputEnabled = true + }; + + ChatCompletion completion = await client.CompleteChatAsync( + ["Empty options test: Say 'Hello'"], + createOptions); + + Thread.Sleep(5000); // Wait for completion to be stored + + // Test with default/empty options + int count = 0; + await foreach (var fetchedCompletion in client.GetChatCompletionsAsync()) + { + count++; + Assert.That(fetchedCompletion.Id, Is.Not.Null.And.Not.Empty); + Assert.That(fetchedCompletion.Content, Is.Not.Null); + if (count >= 3) break; // Limit for test performance + } + + Assert.That(count, Is.GreaterThan(0)); + + // Clean up + try + { + await client.DeleteChatCompletionAsync(completion.Id); + } + catch { /* Ignore cleanup errors */ } + } + + [Test] + public async Task GetChatCompletionsWithCombinedFilters() + { + ChatClient client = GetTestClient(); + + // Create completion with combined metadata for filtering + var testKey = $"combined_test_{Guid.NewGuid():N}"; + ChatCompletionOptions createOptions = new() + { + StoredOutputEnabled = true, + Metadata = + { + [testKey] = "combined_value", + ["test_type"] = "integration" + } + }; + + ChatCompletion completion = await client.CompleteChatAsync( + ["Combined filters test: Say 'Combined test'"], + createOptions); + + Thread.Sleep(5000); // Wait for completion to be stored + + // Test with combined filters + ChatCompletionCollectionOptions combinedOptions = new() + { + PageSizeLimit = 5, + Order = ChatCompletionCollectionOrder.Desc, + Metadata = { [testKey] = "combined_value" } + }; + + int count = 0; + + await foreach (var fetchedCompletion in client.GetChatCompletionsAsync(combinedOptions)) + { + count++; + Assert.That(fetchedCompletion.Id, Is.Not.Null.And.Not.Empty); + + if (count >= 10) break; // Prevent excessive iterations + } + + Assert.That(count, Is.GreaterThan(0)); + + // Clean up + try + { + await client.DeleteChatCompletionAsync(completion.Id); + } + catch { /* Ignore cleanup errors */ } + } + [Test] public async Task FileIdContentWorks() { @@ -1162,6 +1555,143 @@ private void Validate(T item) } } + [Test] + public async Task GetChatCompletionsValidatesCollectionEnumeration() + { + ChatClient client = GetTestClient(); + + // Create a completion to ensure we have data + ChatCompletionOptions createOptions = new() + { + StoredOutputEnabled = true, + Metadata = { ["enumeration_test"] = "true" } + }; + + ChatCompletion completion = await client.CompleteChatAsync( + ["Enumeration test: Say 'Test enumeration'"], + createOptions); + + Thread.Sleep(5000); // Wait for completion to be stored + + // Test that we can enumerate multiple times + ChatCompletionCollectionOptions collectionOptions = new() + { + PageSizeLimit = 2 + }; + + var collection = client.GetChatCompletionsAsync(collectionOptions); + + // First enumeration + int firstCount = 0; + await foreach (var item in collection) + { + firstCount++; + Assert.That(item.Id, Is.Not.Null.And.Not.Empty); + if (firstCount >= 2) break; + } + + // Second enumeration (should work independently) + int secondCount = 0; + await foreach (var item in collection) + { + secondCount++; + Assert.That(item.Id, Is.Not.Null.And.Not.Empty); + if (secondCount >= 2) break; + } + + Assert.That(firstCount, Is.GreaterThan(0)); + Assert.That(secondCount, Is.GreaterThan(0)); + + // Clean up + try + { + await client.DeleteChatCompletionAsync(completion.Id); + } + catch { /* Ignore cleanup errors */ } + } + + [Test] + public async Task GetChatCompletionsHandlesLargeLimits() + { + ChatClient client = GetTestClient(); + + // Create a completion for testing + ChatCompletionOptions createOptions = new() + { + StoredOutputEnabled = true + }; + + ChatCompletion completion = await client.CompleteChatAsync( + ["Large limit test: Say 'Testing large limits'"], + createOptions); + + Thread.Sleep(5000); // Wait for completion to be stored + + // Test with a large page size limit + ChatCompletionCollectionOptions largeOptions = new() + { + PageSizeLimit = 100 + }; + + int count = 0; + await foreach (var fetchedCompletion in client.GetChatCompletionsAsync(largeOptions)) + { + count++; + Assert.That(fetchedCompletion.Id, Is.Not.Null.And.Not.Empty); + if (count >= 20) break; // Prevent excessive test time + } + + Assert.That(count, Is.GreaterThan(0)); + + // Clean up + try + { + await client.DeleteChatCompletionAsync(completion.Id); + } + catch { /* Ignore cleanup errors */ } + } + + [Test] + public async Task GetChatCompletionsWithMinimalLimits() + { + ChatClient client = GetTestClient(); + + // Create a completion for testing + ChatCompletionOptions createOptions = new() + { + StoredOutputEnabled = true + }; + + ChatCompletion completion = await client.CompleteChatAsync( + ["Minimal limit test: Say 'Testing minimal limits'"], + createOptions); + + Thread.Sleep(5000); // Wait for completion to be stored + + // Test with minimal page size + ChatCompletionCollectionOptions minimalOptions = new() + { + PageSizeLimit = 1 + }; + + int count = 0; + await foreach (var fetchedCompletion in client.GetChatCompletionsAsync(minimalOptions)) + { + count++; + Assert.That(fetchedCompletion.Id, Is.Not.Null.And.Not.Empty); + if (count >= 3) break; // Get a few items to verify pagination works + } + + Assert.That(count, Is.GreaterThan(0)); + + // Clean up + try + { + await client.DeleteChatCompletionAsync(completion.Id); + } + catch { /* Ignore cleanup errors */ } + } + [OneTimeTearDown] public void TearDown() { From 62ba97effc0221c7e0e685a651729f7d11680ef9 Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Wed, 23 Jul 2025 10:37:35 -0500 Subject: [PATCH 06/11] add readme for debugging the generator --- codegen/README.MD | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 codegen/README.MD diff --git a/codegen/README.MD b/codegen/README.MD new file mode 100644 index 000000000..bdc587d4f --- /dev/null +++ b/codegen/README.MD @@ -0,0 +1,23 @@ +# Debugging the generator + +To configure VS Code for debugging the generator, specifically visitors, add the following to your `launch.json` in the root of the workspace + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug OpenAI Library Plugin", + "type": "coreclr", + "request": "launch", + "program": "dotnet", + "args": [ + "${workspaceFolder}/codegen/dist/generator/Microsoft.TypeSpec.Generator.dll", + "${workspaceFolder}", + "-g", + "OpenAILibraryGenerator" + ], + } + ] +} +``` \ No newline at end of file From edb42b933ee23a75fb3dfe513fc1d164a3a7bd8a Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Wed, 23 Jul 2025 11:06:41 -0500 Subject: [PATCH 07/11] fb --- .../src/Visitors/MetadataQueryParamVisitor.cs | 4 +-- .../src/Visitors/PaginationVisitor.cs | 28 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/codegen/generator/src/Visitors/MetadataQueryParamVisitor.cs b/codegen/generator/src/Visitors/MetadataQueryParamVisitor.cs index 626f939eb..38efadccf 100644 --- a/codegen/generator/src/Visitors/MetadataQueryParamVisitor.cs +++ b/codegen/generator/src/Visitors/MetadataQueryParamVisitor.cs @@ -103,10 +103,10 @@ dictionaryExpression.Original is VariableExpression variable && variable.Declaration.RequestedName == "metadata") { var formatString = new FormattableStringExpression("metadata[{0}]", [foreachStatement.ItemVariable.Property("Key")]); - var appendQueryStatement = uri.Invoke("AppendQuery", [formatString, foreachStatement.ItemVariable.Property("Value"), new KeywordExpression("true", null)]); + var appendQueryStatement = uri.Invoke("AppendQuery", [formatString, foreachStatement.ItemVariable.Property("Value"), Snippet.True]); foreachStatement.Body.Clear(); foreachStatement.Body.Add(new SingleLineCommentStatement("Plugin customization: Properly handle metadata query parameters")); - foreachStatement.Body.Add(new ExpressionStatement(appendQueryStatement)); + foreachStatement.Body.Add(appendQueryStatement.Terminate()); } // Remove the call to AppendQueryDelimited for metadata diff --git a/codegen/generator/src/Visitors/PaginationVisitor.cs b/codegen/generator/src/Visitors/PaginationVisitor.cs index 2c0ab10a9..e393ffb1e 100644 --- a/codegen/generator/src/Visitors/PaginationVisitor.cs +++ b/codegen/generator/src/Visitors/PaginationVisitor.cs @@ -93,20 +93,20 @@ private bool TryHandlePaginationMethodWithOptions(MethodProvider method) { newParameters.Insert( lastRemovedIndex, - new ParameterProvider("options", $"The pagination options", optionsType.Type, defaultValue: new KeywordExpression("default", null))); + new ParameterProvider("options", $"The pagination options", optionsType.Type, defaultValue: Snippet.Default)); var newSignature = new MethodSignature( - methodSignature.Name, - methodSignature.Description, - methodSignature.Modifiers, - methodSignature.ReturnType, - methodSignature.ReturnDescription, - newParameters, - methodSignature.Attributes, - methodSignature.GenericArguments, - methodSignature.GenericParameterConstraints, - methodSignature.ExplicitInterface, - methodSignature.NonDocumentComment); + methodSignature.Name, + methodSignature.Description, + methodSignature.Modifiers, + methodSignature.ReturnType, + methodSignature.ReturnDescription, + newParameters, + methodSignature.Attributes, + methodSignature.GenericArguments, + methodSignature.GenericParameterConstraints, + methodSignature.ExplicitInterface, + methodSignature.NonDocumentComment); var optionsParam = newParameters[lastRemovedIndex]; @@ -212,7 +212,7 @@ binaryExpr.Right is KeywordExpression rightKeyword && var hasMoreNullCheck = new BinaryOperatorExpression( "==", new MemberExpression(null, "hasMore"), - new KeywordExpression("false", null)); + Snippet.False); // Return "nextToken == null || hasMore == null" return new BinaryOperatorExpression("||", binaryExpr, hasMoreNullCheck); @@ -244,7 +244,7 @@ assignmentExpression.Value is MemberExpression memberExpression && new MemberExpression(memberExpression.Inner, "HasMore")); // Insert the new assignment before the existing one - statementList.Insert(i, new ExpressionStatement(hasMoreAssignment)); + statementList.Insert(i, hasMoreAssignment.Terminate()); statementList.Insert(i, new SingleLineCommentStatement("Plugin customization: add hasMore assignment")); var updatedWhileStatement = new WhileStatement(whileStatement.Condition); foreach (MethodBodyStatement bodyStatement in statementList) From c02ccc3cc24c9269f62c2c2d275799129b7c05a2 Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Wed, 23 Jul 2025 11:10:46 -0500 Subject: [PATCH 08/11] fb --- codegen/generator/src/Visitors/PaginationVisitor.cs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/codegen/generator/src/Visitors/PaginationVisitor.cs b/codegen/generator/src/Visitors/PaginationVisitor.cs index e393ffb1e..c921f8a65 100644 --- a/codegen/generator/src/Visitors/PaginationVisitor.cs +++ b/codegen/generator/src/Visitors/PaginationVisitor.cs @@ -152,17 +152,7 @@ nullConditional.Inner is VariableExpression varExpr2 && } } // Create a new ExpressionStatement with the same children as the original, but with the new parameters. - var newNewInstanceExpression = new NewInstanceExpression( - newInstance.Type, - newParameters); - - var newKeywordExpression = new KeywordExpression( - keyword.Keyword, - newNewInstanceExpression); - - var newExpressionStatement = new ExpressionStatement(newKeywordExpression); - - return newExpressionStatement; + return Snippet.Return(Snippet.New.Instance(newInstance.Type!, newParameters)); } } return statement; From 5f2db73165eec489b280f193b6f344b25f6fa0b1 Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Mon, 28 Jul 2025 13:52:26 -0500 Subject: [PATCH 09/11] fb --- api/OpenAI.net8.0.cs | 35 +++++++++++++++++++ api/OpenAI.netstandard2.0.cs | 29 +++++++++++++++ specification/client/models/chat.models.tsp | 4 +-- specification/main.tsp | 2 +- .../Chat/ChatCompletionCollectionOptions.cs | 4 +++ .../Chat/ChatCompletionCollectionOrder.cs | 4 +++ src/Custom/Chat/Internal/GeneratorStubs.cs | 4 +-- .../Chat/ChatCompletionCollectionOrder.cs | 8 ++--- src/Generated/OpenAIModelFactory.cs | 10 +++--- tests/Chat/ChatTests.cs | 6 ++-- 10 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 src/Custom/Chat/ChatCompletionCollectionOptions.cs create mode 100644 src/Custom/Chat/ChatCompletionCollectionOrder.cs diff --git a/api/OpenAI.net8.0.cs b/api/OpenAI.net8.0.cs index 57bff3c5d..7ed0660f4 100644 --- a/api/OpenAI.net8.0.cs +++ b/api/OpenAI.net8.0.cs @@ -1430,6 +1430,14 @@ public class ChatClient { public virtual Task GetChatCompletionAsync(string completionId, RequestOptions options); [Experimental("OPENAI001")] public virtual Task> GetChatCompletionAsync(string completionId, CancellationToken cancellationToken = default); + [Experimental("OPENAI001")] + public virtual CollectionResult GetChatCompletions(ChatCompletionCollectionOptions options = null, CancellationToken cancellationToken = default); + [Experimental("OPENAI001")] + public virtual CollectionResult GetChatCompletions(string after, int? limit, string order, IDictionary metadata, string model, RequestOptions options); + [Experimental("OPENAI001")] + public virtual AsyncCollectionResult GetChatCompletionsAsync(ChatCompletionCollectionOptions options = null, CancellationToken cancellationToken = default); + [Experimental("OPENAI001")] + public virtual AsyncCollectionResult GetChatCompletionsAsync(string after, int? limit, string order, IDictionary metadata, string model, RequestOptions options); } public class ChatCompletion : IJsonModel, IPersistableModel { [Experimental("OPENAI001")] @@ -1460,6 +1468,33 @@ public class ChatCompletion : IJsonModel, IPersistableModel, IPersistableModel { + public string AfterId { get; set; } + public IDictionary Metadata { get; } + public string Model { get; set; } + public ChatCompletionCollectionOrder? Order { get; set; } + public int? PageSizeLimit { get; set; } + protected virtual ChatCompletionCollectionOptions JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options); + protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options); + protected virtual ChatCompletionCollectionOptions PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options); + protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options); + } + [Experimental("OPENAI001")] + public readonly partial struct ChatCompletionCollectionOrder : IEquatable { + public ChatCompletionCollectionOrder(string value); + public static ChatCompletionCollectionOrder Ascending { get; } + public static ChatCompletionCollectionOrder Descending { get; } + public readonly bool Equals(ChatCompletionCollectionOrder other); + [EditorBrowsable(EditorBrowsableState.Never)] + public override readonly bool Equals(object obj); + [EditorBrowsable(EditorBrowsableState.Never)] + public override readonly int GetHashCode(); + public static bool operator ==(ChatCompletionCollectionOrder left, ChatCompletionCollectionOrder right); + public static implicit operator ChatCompletionCollectionOrder(string value); + public static bool operator !=(ChatCompletionCollectionOrder left, ChatCompletionCollectionOrder right); + public override readonly string ToString(); + } + [Experimental("OPENAI001")] public class ChatCompletionDeletionResult : IJsonModel, IPersistableModel { public string ChatCompletionId { get; } public bool Deleted { get; } diff --git a/api/OpenAI.netstandard2.0.cs b/api/OpenAI.netstandard2.0.cs index 10c9b626b..86ff44b58 100644 --- a/api/OpenAI.netstandard2.0.cs +++ b/api/OpenAI.netstandard2.0.cs @@ -1285,6 +1285,10 @@ public class ChatClient { public virtual ClientResult GetChatCompletion(string completionId, CancellationToken cancellationToken = default); public virtual Task GetChatCompletionAsync(string completionId, RequestOptions options); public virtual Task> GetChatCompletionAsync(string completionId, CancellationToken cancellationToken = default); + public virtual CollectionResult GetChatCompletions(ChatCompletionCollectionOptions options = null, CancellationToken cancellationToken = default); + public virtual CollectionResult GetChatCompletions(string after, int? limit, string order, IDictionary metadata, string model, RequestOptions options); + public virtual AsyncCollectionResult GetChatCompletionsAsync(ChatCompletionCollectionOptions options = null, CancellationToken cancellationToken = default); + public virtual AsyncCollectionResult GetChatCompletionsAsync(string after, int? limit, string order, IDictionary metadata, string model, RequestOptions options); } public class ChatCompletion : IJsonModel, IPersistableModel { public IReadOnlyList Annotations { get; } @@ -1308,6 +1312,31 @@ public class ChatCompletion : IJsonModel, IPersistableModel, IPersistableModel { + public string AfterId { get; set; } + public IDictionary Metadata { get; } + public string Model { get; set; } + public ChatCompletionCollectionOrder? Order { get; set; } + public int? PageSizeLimit { get; set; } + protected virtual ChatCompletionCollectionOptions JsonModelCreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options); + protected virtual void JsonModelWriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options); + protected virtual ChatCompletionCollectionOptions PersistableModelCreateCore(BinaryData data, ModelReaderWriterOptions options); + protected virtual BinaryData PersistableModelWriteCore(ModelReaderWriterOptions options); + } + public readonly partial struct ChatCompletionCollectionOrder : IEquatable { + public ChatCompletionCollectionOrder(string value); + public static ChatCompletionCollectionOrder Ascending { get; } + public static ChatCompletionCollectionOrder Descending { get; } + public readonly bool Equals(ChatCompletionCollectionOrder other); + [EditorBrowsable(EditorBrowsableState.Never)] + public override readonly bool Equals(object obj); + [EditorBrowsable(EditorBrowsableState.Never)] + public override readonly int GetHashCode(); + public static bool operator ==(ChatCompletionCollectionOrder left, ChatCompletionCollectionOrder right); + public static implicit operator ChatCompletionCollectionOrder(string value); + public static bool operator !=(ChatCompletionCollectionOrder left, ChatCompletionCollectionOrder right); + public override readonly string ToString(); + } public class ChatCompletionDeletionResult : IJsonModel, IPersistableModel { public string ChatCompletionId { get; } public bool Deleted { get; } diff --git a/specification/client/models/chat.models.tsp b/specification/client/models/chat.models.tsp index 28d8b7184..8f239b501 100644 --- a/specification/client/models/chat.models.tsp +++ b/specification/client/models/chat.models.tsp @@ -17,8 +17,8 @@ alias ChatCompletionCollectionOrderQueryParameter = { union ChatCompletionCollectionOrder { string, - Asc: "asc", - Desc: "desc", + Ascending: "asc", + Descending: "desc", } @access(Access.public) diff --git a/specification/main.tsp b/specification/main.tsp index 450573134..db58af760 100644 --- a/specification/main.tsp +++ b/specification/main.tsp @@ -15,9 +15,9 @@ import "./client/threads.client.tsp"; import "./client/vector-stores.client.tsp"; import "./client/models/audio.models.tsp"; +import "./client/models/chat.models.tsp"; import "./client/models/common.models.tsp"; import "./client/models/responses.models.tsp"; import "./client/models/vector-stores.models.tsp"; -import "./client/models/chat.models.tsp"; import "./base/entrypoints/sdk.dotnet"; diff --git a/src/Custom/Chat/ChatCompletionCollectionOptions.cs b/src/Custom/Chat/ChatCompletionCollectionOptions.cs new file mode 100644 index 000000000..be39318be --- /dev/null +++ b/src/Custom/Chat/ChatCompletionCollectionOptions.cs @@ -0,0 +1,4 @@ +namespace OpenAI.Chat; + +// CUSTOM: Make public and use the correct namespace. +[CodeGenType("ChatCompletionCollectionOptions")] public partial class ChatCompletionCollectionOptions { } \ No newline at end of file diff --git a/src/Custom/Chat/ChatCompletionCollectionOrder.cs b/src/Custom/Chat/ChatCompletionCollectionOrder.cs new file mode 100644 index 000000000..3dc393eeb --- /dev/null +++ b/src/Custom/Chat/ChatCompletionCollectionOrder.cs @@ -0,0 +1,4 @@ +namespace OpenAI.Chat; + +// CUSTOM: Make public and use the correct namespace. +[CodeGenType("ChatCompletionCollectionOrder")] public readonly partial struct ChatCompletionCollectionOrder { } \ No newline at end of file diff --git a/src/Custom/Chat/Internal/GeneratorStubs.cs b/src/Custom/Chat/Internal/GeneratorStubs.cs index bcdb80c9c..9e5acc63e 100644 --- a/src/Custom/Chat/Internal/GeneratorStubs.cs +++ b/src/Custom/Chat/Internal/GeneratorStubs.cs @@ -120,6 +120,4 @@ internal partial class InternalUnknownChatCompletionRequestMessageContentPart { [CodeGenType("ChatCompletionDeletedObject")] internal readonly partial struct InternalChatCompletionDeletedObject {} [CodeGenType("ChatCompletionMessageListObject")] internal readonly partial struct InternalChatCompletionMessageListObject {} [CodeGenType("ChatCompletionList")] internal partial class InternalChatCompletionList {} -[CodeGenType("ChatCompletionMessageList")] internal partial class InternalChatCompletionMessageList {} -[CodeGenType("ChatCompletionCollectionOptions")] public partial class ChatCompletionCollectionOptions {} -[CodeGenType("ChatCompletionCollectionOrder")] public readonly partial struct ChatCompletionCollectionOrder { } \ No newline at end of file +[CodeGenType("ChatCompletionMessageList")] internal partial class InternalChatCompletionMessageList {} \ No newline at end of file diff --git a/src/Generated/Models/Chat/ChatCompletionCollectionOrder.cs b/src/Generated/Models/Chat/ChatCompletionCollectionOrder.cs index bac255c46..414bb39bb 100644 --- a/src/Generated/Models/Chat/ChatCompletionCollectionOrder.cs +++ b/src/Generated/Models/Chat/ChatCompletionCollectionOrder.cs @@ -13,8 +13,8 @@ namespace OpenAI.Chat public readonly partial struct ChatCompletionCollectionOrder : IEquatable { private readonly string _value; - private const string AscValue = "asc"; - private const string DescValue = "desc"; + private const string AscendingValue = "asc"; + private const string DescendingValue = "desc"; public ChatCompletionCollectionOrder(string value) { @@ -23,9 +23,9 @@ public ChatCompletionCollectionOrder(string value) _value = value; } - public static ChatCompletionCollectionOrder Asc { get; } = new ChatCompletionCollectionOrder(AscValue); + public static ChatCompletionCollectionOrder Ascending { get; } = new ChatCompletionCollectionOrder(AscendingValue); - public static ChatCompletionCollectionOrder Desc { get; } = new ChatCompletionCollectionOrder(DescValue); + public static ChatCompletionCollectionOrder Descending { get; } = new ChatCompletionCollectionOrder(DescendingValue); public static bool operator ==(ChatCompletionCollectionOrder left, ChatCompletionCollectionOrder right) => left.Equals(right); diff --git a/src/Generated/OpenAIModelFactory.cs b/src/Generated/OpenAIModelFactory.cs index 844502fcb..72c0f256b 100644 --- a/src/Generated/OpenAIModelFactory.cs +++ b/src/Generated/OpenAIModelFactory.cs @@ -1070,11 +1070,6 @@ public static AudioTranscription AudioTranscription(string language = default, s additionalBinaryDataProperties: null); } - public static AudioTokenLogProbabilityDetails AudioTokenLogProbabilityDetails(string token = default, float logProbability = default, ReadOnlyMemory utf8Bytes = default) - { - return new AudioTokenLogProbabilityDetails(token, logProbability, utf8Bytes, additionalBinaryDataProperties: null); - } - public static ChatCompletionCollectionOptions ChatCompletionCollectionOptions(string afterId = default, int? pageSizeLimit = default, ChatCompletionCollectionOrder? order = default, IDictionary metadata = default, string model = default) { metadata ??= new ChangeTrackingDictionary(); @@ -1088,6 +1083,11 @@ public static ChatCompletionCollectionOptions ChatCompletionCollectionOptions(st additionalBinaryDataProperties: null); } + public static AudioTokenLogProbabilityDetails AudioTokenLogProbabilityDetails(string token = default, float logProbability = default, ReadOnlyMemory utf8Bytes = default) + { + return new AudioTokenLogProbabilityDetails(token, logProbability, utf8Bytes, additionalBinaryDataProperties: null); + } + public static ContainerListResource ContainerListResource(string @object = default, IEnumerable data = default, string firstId = default, string lastId = default, bool hasMore = default) { data ??= new ChangeTrackingList(); diff --git a/tests/Chat/ChatTests.cs b/tests/Chat/ChatTests.cs index d4721e4e3..35cd5193f 100644 --- a/tests/Chat/ChatTests.cs +++ b/tests/Chat/ChatTests.cs @@ -1213,7 +1213,7 @@ public async Task GetChatCompletionsWithOrderFiltering() // Test ascending order ChatCompletionCollectionOptions ascOptions = new() { - Order = ChatCompletionCollectionOrder.Asc, + Order = ChatCompletionCollectionOrder.Ascending, PageSizeLimit = 5 }; @@ -1227,7 +1227,7 @@ public async Task GetChatCompletionsWithOrderFiltering() // Test descending order ChatCompletionCollectionOptions descOptions = new() { - Order = ChatCompletionCollectionOrder.Desc, + Order = ChatCompletionCollectionOrder.Descending, PageSizeLimit = 5 }; @@ -1430,7 +1430,7 @@ public async Task GetChatCompletionsWithCombinedFilters() ChatCompletionCollectionOptions combinedOptions = new() { PageSizeLimit = 5, - Order = ChatCompletionCollectionOrder.Desc, + Order = ChatCompletionCollectionOrder.Descending, Metadata = { [testKey] = "combined_value" } }; From 982d2392f1a378fd1a066c26d1f4cf92aa488a5e Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Tue, 29 Jul 2025 13:19:03 -0500 Subject: [PATCH 10/11] fb --- .../src/Visitors/MetadataQueryParamVisitor.cs | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/codegen/generator/src/Visitors/MetadataQueryParamVisitor.cs b/codegen/generator/src/Visitors/MetadataQueryParamVisitor.cs index 38efadccf..dd764ad09 100644 --- a/codegen/generator/src/Visitors/MetadataQueryParamVisitor.cs +++ b/codegen/generator/src/Visitors/MetadataQueryParamVisitor.cs @@ -12,33 +12,12 @@ namespace OpenAILibraryPlugin.Visitors; /// -/// This visitor modifies GetRawPagesAsync methods to consider HasMore in addition to LastId when deciding whether to continue pagination. -/// It also replaces specific parameters with an options type for pagination methods. +/// This visitor fixes up usage of the metadata query parameter into the proper format. /// public class MetadataQueryParamVisitor : ScmLibraryVisitor { private static readonly string[] _chatParamsToReplace = ["after", "before", "limit", "order", "model", "metadata"]; - private static readonly Dictionary _paramReplacementMap = new() - { - { "after", "AfterId" }, - { "before", "LastId" }, - { "limit", "PageSizeLimit" }, - { "order", "Order" }, - { "model", "Model" }, - { "metadata", "Metadata" } - }; - private static readonly Dictionary _optionsReplacements = new() - { - { - "GetChatCompletions", - ("ChatCompletion", "ChatCompletionCollectionOptions", _chatParamsToReplace) - }, - { - "GetChatCompletionsAsync", - ("ChatCompletion", "ChatCompletionCollectionOptions", _chatParamsToReplace) - } - }; /// /// Visits Create*Request methods to modify how metadata query parameters are handled. From 016b08d8838179d7f32f0894f6aad3dc95a97a31 Mon Sep 17 00:00:00 2001 From: Christopher Scott Date: Tue, 29 Jul 2025 13:25:59 -0500 Subject: [PATCH 11/11] fb --- tests/Chat/ChatTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Chat/ChatTests.cs b/tests/Chat/ChatTests.cs index 35cd5193f..6b63c4fea 100644 --- a/tests/Chat/ChatTests.cs +++ b/tests/Chat/ChatTests.cs @@ -1352,7 +1352,7 @@ public async Task GetChatCompletionsWithModelFiltering() { count++; Assert.That(fetchedCompletion.Id, Is.Not.Null.And.Not.Empty); - // Note: The actual model filtering behavior depends on the service implementation + Assert.That(fetchedCompletion.Model, Is.EqualTo(filterOptions.Model)); if (count >= 5) break; // Limit results for test performance }