diff --git a/.dotnet/Directory.Build.props b/.dotnet/Directory.Build.props
new file mode 100644
index 000000000..a95ac958c
--- /dev/null
+++ b/.dotnet/Directory.Build.props
@@ -0,0 +1,5 @@
+
+
+ latest
+
+
\ No newline at end of file
diff --git a/.dotnet/OpenAI.sln b/.dotnet/OpenAI.sln
new file mode 100644
index 000000000..5d1edd8c3
--- /dev/null
+++ b/.dotnet/OpenAI.sln
@@ -0,0 +1,50 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29709.97
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenAI", "src\OpenAI.csproj", "{28FF4005-4467-4E36-92E7-DEA27DEB1519}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenAI.Tests", "tests\OpenAI.Tests.csproj", "{1F1CD1D4-9932-4B73-99D8-C252A67D4B46}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8E9A77AC-792A-4432-8320-ACFD46730401}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8E9A77AC-792A-4432-8320-ACFD46730401}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8E9A77AC-792A-4432-8320-ACFD46730401}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8E9A77AC-792A-4432-8320-ACFD46730401}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A4241C1F-A53D-474C-9E4E-075054407E74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A4241C1F-A53D-474C-9E4E-075054407E74}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A4241C1F-A53D-474C-9E4E-075054407E74}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A4241C1F-A53D-474C-9E4E-075054407E74}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {A97F4B90-2591-4689-B1F8-5F21FE6D6CAE}
+ EndGlobalSection
+EndGlobal
diff --git a/.dotnet/scripts/Add-Customizations.ps1 b/.dotnet/scripts/Add-Customizations.ps1
new file mode 100644
index 000000000..c7eb4412b
--- /dev/null
+++ b/.dotnet/scripts/Add-Customizations.ps1
@@ -0,0 +1,28 @@
+function Update-SystemTextJsonPackage {
+ $current = Get-Location
+ $root = Split-Path $PSScriptRoot -Parent
+
+ # Update System.Text.Json package to 8.0.2 in OpenAI.csproj
+ $directory = Join-Path -Path $root -ChildPath "src"
+ Set-Location -Path $directory
+ dotnet remove "OpenAI.csproj" package "System.Text.Json"
+ dotnet add "OpenAI.csproj" package "System.Text.Json" --version "8.0.2"
+
+ Set-Location -Path $current
+}
+
+function Update-MicrosoftBclAsyncInterfacesPackage {
+ $current = Get-Location
+ $root = Split-Path $PSScriptRoot -Parent
+
+ # Update Microsoft.Bcl.AsyncInterfaces package to 8.0.0 in OpenAI.Tests.csproj
+ $directory = Join-Path -Path $root -ChildPath "tests"
+ Set-Location -Path $directory
+ dotnet remove "OpenAI.Tests.csproj" package "Microsoft.Bcl.AsyncInterfaces"
+ dotnet add "OpenAI.Tests.csproj" package "Microsoft.Bcl.AsyncInterfaces" --version "8.0.0"
+
+ Set-Location -Path $current
+}
+
+Update-SystemTextJsonPackage
+Update-MicrosoftBclAsyncInterfacesPackage
\ No newline at end of file
diff --git a/.dotnet/scripts/ConvertTo-Internal.ps1 b/.dotnet/scripts/ConvertTo-Internal.ps1
new file mode 100644
index 000000000..60f66e75e
--- /dev/null
+++ b/.dotnet/scripts/ConvertTo-Internal.ps1
@@ -0,0 +1,41 @@
+function Edit-GeneratedSources {
+ $root = Split-Path $PSScriptRoot -Parent
+
+ $directory = Join-Path -Path $root -ChildPath "src\Generated"
+ $files = Get-ChildItem -Path $($directory + "\*") -Include "*.cs" -Recurse
+
+ foreach ($file in $files) {
+ $content = Get-Content -Path $file -Raw
+
+ Write-Output "Editing $($file.FullName)"
+
+ $content = $content -creplace "public partial class", "internal partial class"
+ $content = $content -creplace "public readonly partial struct", "internal readonly partial struct"
+ $content = $content -creplace "public static partial class", "internal static partial class"
+ $content = $content -creplace "namespace OpenAI", "namespace OpenAI.Internal"
+ $content = $content -creplace "using OpenAI.Models;", "using OpenAI.Internal.Models;"
+
+ $content | Set-Content -Path $file.FullName -NoNewline
+ }
+
+ $file = Get-ChildItem -Path $directory -Filter "OpenAIClient.cs"
+ $content = Get-Content -Path $file -Raw
+
+ Write-Output "Editing $($file.FullName)"
+
+ $content = $content -creplace "private (OpenAI.)?(?\w+) _cached(\w+);", "private OpenAI.Internal.`${var} _cached`${var};"
+ $content = $content -creplace "public virtual (OpenAI.)?(?\w+) Get(\w+)Client", "public virtual OpenAI.Internal.`${var} Get`${var}Client"
+ $content = $content -creplace "ref _cached(\w+), new (OpenAI.)?(?\w+)", "ref _cached`${var}, new OpenAI.Internal.`${var}"
+
+ $content | Set-Content -Path $file.FullName -NoNewline
+}
+
+function Remove-GeneratedTests {
+ $root = Split-Path $PSScriptRoot -Parent
+
+ $directory = Join-Path -Path $root -ChildPath "tests\Generated"
+ Remove-Item -LiteralPath $directory -Recurse -Force
+}
+
+Edit-GeneratedSources
+Remove-GeneratedTests
diff --git a/.dotnet/scripts/Update-ClientModel.ps1 b/.dotnet/scripts/Update-ClientModel.ps1
new file mode 100644
index 000000000..a833fc8b7
--- /dev/null
+++ b/.dotnet/scripts/Update-ClientModel.ps1
@@ -0,0 +1,204 @@
+function Update-SystemClientModelPackage {
+ $current = Get-Location
+ $root = Split-Path $PSScriptRoot -Parent
+
+ # Update System.ClientModel package in OpenAI.csproj
+ $directory = Join-Path -Path $root -ChildPath "src"
+ Set-Location -Path $directory
+ dotnet remove "OpenAI.csproj" package "System.ClientModel"
+ dotnet add "OpenAI.csproj" package "System.ClientModel" --version "1.1.0-alpha.20240227.1" --source "https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json"
+
+ # Update System.ClientModel package in OpenAI.Tests.csproj
+ $directory = Join-Path -Path $root -ChildPath "tests"
+ Set-Location -Path $directory
+ dotnet remove "OpenAI.Tests.csproj" package "System.ClientModel"
+ dotnet add "OpenAI.Tests.csproj" package "System.ClientModel" --version "1.1.0-alpha.20240227.1" --source "https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json"
+
+ Set-Location -Path $current
+}
+
+function Update-OpenAIClient {
+ $root = Split-Path $PSScriptRoot -Parent
+ $directory = Join-Path -Path $root -ChildPath "src\Generated"
+ $file = Get-ChildItem -Path $directory -Filter "OpenAIClient.cs"
+ $content = Get-Content -Path $file -Raw
+
+ Write-Output "Editing $($file.FullName)"
+
+ $content = $content -creplace "\s+#nullable disable", ""
+ $content = $content -creplace "\s+using System\.ClientModel\.Internal;", ""
+ $content = $content -creplace "\s+using System\.ClientModel\.Primitives\.Pipeline;", ""
+ $content = $content -creplace " KeyCredential ", " ApiKeyCredential "
+ $content = $content -creplace " _keyCredential", " _credential"
+ $content = $content -creplace " MessagePipeline ", " ClientPipeline "
+ $content = $content -creplace "\s+\/\/\/ The ClientDiagnostics is used to provide tracing support for the client library. ", ""
+ $content = $content -creplace "\s+internal TelemetrySource ClientDiagnostics { get; }", ""
+ $content = $content -creplace "\(KeyCredential", "(ApiKeyCredential"
+ $content = $content -creplace "ClientUtilities.AssertNotNull\((?\w+), nameof\((\w+)\)\);", "if (`${var} is null) throw new ArgumentNullException(nameof(`${var}));"
+ $content = $content -creplace "\s+ClientDiagnostics = new TelemetrySource\(options, true\);", ""
+ $content = $content -creplace "_pipeline = MessagePipeline\.Create\(options, new IPipelinePolicy\[\] \{ new KeyCredentialPolicy\(_keyCredential, AuthorizationHeader, AuthorizationApiKeyPrefix\) \}, Array\.Empty>\(\)\);", "var authenticationPolicy = ApiKeyAuthenticationPolicy.CreateBearerAuthorizationPolicy(_credential);`r`n _pipeline = ClientPipeline.Create(options,`r`n perCallPolicies: ReadOnlySpan.Empty,`r`n perTryPolicies: new PipelinePolicy[] { authenticationPolicy },`r`n beforeTransportPolicies: ReadOnlySpan.Empty);"
+ $content = $content -creplace "\(ClientDiagnostics, ", "("
+
+ $content | Set-Content -Path $file.FullName -NoNewline
+}
+
+function Update-OpenAIClientOptions {
+ $root = Split-Path $PSScriptRoot -Parent
+ $directory = Join-Path -Path $root -ChildPath "src\Generated"
+ $file = Get-ChildItem -Path $directory -Filter "OpenAIClientOptions.cs"
+ $content = Get-Content -Path $file -Raw
+
+ Write-Output "Editing $($file.FullName)"
+
+ $content = $content -creplace "\s+#nullable disable", ""
+ $content = $content -creplace "using System\.ClientModel;", "using System.ClientModel.Primitives;"
+ $content = $content -creplace ": RequestOptions", ": ClientPipelineOptions"
+
+ $content | Set-Content -Path $file.FullName -NoNewline
+}
+
+function Update-Subclients {
+ $root = Split-Path $PSScriptRoot -Parent
+ $directory = Join-Path -Path $root -ChildPath "src\Generated"
+ $files = Get-ChildItem -Path $($directory + "\*") -Include "*.cs" -Exclude "OpenAIClient.cs", "OpenAIClientOptions.cs"
+
+ foreach ($file in $files) {
+ $content = Get-Content -Path $file -Raw
+
+ Write-Output "Editing $($file.FullName)"
+
+ # Delete #nullable
+ $content = $content -creplace "\s+#nullable disable", ""
+
+ # Fix using statements
+ $content = $content -creplace "\s+using System.ClientModel.Internal;", ""
+ $content = $content -creplace "\s+using System.ClientModel.Primitives.Pipeline;", ""
+ $content = $content -creplace "using System.ClientModel.Primitives;", "using System.ClientModel.Primitives;`r`nusing System.Text;"
+
+ # Fix ClientUtilities
+ $content = $content -creplace "ClientUtilities.AssertNotNull\((?\w+), nameof\((\w+)\)\);", "if (`${var} is null) throw new ArgumentNullException(nameof(`${var}));"
+ $content = $content -creplace "ClientUtilities.AssertNotNullOrEmpty\((?\w+), nameof\((\w+)\)\);", "if (`${var} is null) throw new ArgumentNullException(nameof(`${var}));`r`n if (string.IsNullOrEmpty(`${var})) throw new ArgumentException(nameof(`${var}));"
+
+ # Delete TelemetrySource
+ $content = $content -creplace "\s+\/\/\/ The ClientDiagnostics is used to provide tracing support for the client library. ", ""
+ $content = $content -creplace "\s+internal TelemetrySource ClientDiagnostics { get; }", ""
+
+ # Delete FromCancellationToken
+ $content = $content -creplace "(?s)\s+internal static RequestOptions FromCancellationToken\(CancellationToken cancellationToken = default\).*?return new RequestOptions\(\) \{ CancellationToken = cancellationToken \};.*?\}", ""
+
+ # Modify constructor
+ $content = $content -creplace "\s+\/\/\/ The handler for diagnostic messaging in the client. ", ""
+ $content = $content -creplace "", ""
+ $content = $content -creplace "internal (?\w+)\(TelemetrySource clientDiagnostics, MessagePipeline pipeline, KeyCredential keyCredential, Uri endpoint\)", "internal `${name}(ClientPipeline pipeline, ApiKeyCredential credential, Uri endpoint)"
+ $content = $content -creplace "\s+ClientDiagnostics = clientDiagnostics;", ""
+
+ # # Modify convenience methods
+ $content = $content -creplace "\s+\/\/\/ The cancellation token to use. ", ""
+ $content = $content -creplace "\(CancellationToken cancellationToken = default\)", "()"
+ $content = $content -creplace ", CancellationToken cancellationToken = default\)", ")"
+ $content = $content -creplace "RequestOptions context = FromCancellationToken\(cancellationToken\);\s+", ""
+ $content = $content -creplace "using RequestBody content = (?\w+)\.ToRequestBody\(\);", "using BinaryContent content = BinaryContent.Create(`${var});"
+ $content = $content -creplace "using RequestBody content0 = (?\w+)\.ToRequestBody\(\);", "using BinaryContent content0 = BinaryContent.Create(`${var});"
+ $content = $content -creplace "Result result = await (?\w+)\(context\)\.ConfigureAwait\(false\);", "ClientResult result = await `${method}(DefaultRequestContext).ConfigureAwait(false);"
+ $content = $content -creplace "Result result = (?\w+)\(context\);", "ClientResult result = `${method}(DefaultRequestContext);"
+ $content = $content -creplace "Result result = await (?\w+)\((?[(\w+)(\?.ToString\(\)*)(,\s\w+)]*), context\)\.ConfigureAwait\(false\);", "ClientResult result = await `${method}(`${params}, DefaultRequestContext).ConfigureAwait(false);"
+ $content = $content -creplace "Result result = (?\w+)\((?[(\w+)(\?.ToString\(\)*)(,\s\w+)]*), context\);", "ClientResult result = `${method}(`${params}, DefaultRequestContext);"
+
+ # Modify protocol methods
+ $content = $content -creplace "\/\/\/ Please try the simpler \w+)\(CancellationToken\)`"/> convenience overload with strongly typed models first.", "/// Please try the simpler convenience overload with strongly typed models first."
+ $content = $content -creplace "\/\/\/ Please try the simpler \w+)\((?[(\w+)(\?*)(,\s\w+)]*),CancellationToken\)`"/> convenience overload with strongly typed models first.", "/// Please try the simpler convenience overload with strongly typed models first."
+ $content = $content -creplace "\/\/\/ The request context, which can override default behaviors of the client pipeline on a per-call basis. ", "/// The request options, which can override default behaviors of the client pipeline on a per-call basis. "
+ $content = $content -creplace "\/\/\/ ", "/// "
+ $content = $content -creplace " Task ", " Task "
+ $content = $content -creplace " Result ", " ClientResult "
+ $content = $content -creplace "\(RequestBody content", "(BinaryContent content"
+ $content = $content -creplace " RequestBody content", " BinaryContent content"
+ $content = $content -creplace "\(RequestOptions context", "(RequestOptions options"
+ $content = $content -creplace " RequestOptions context", " RequestOptions options"
+ $content = $content -creplace "\s+using var scope = ClientDiagnostics\.CreateSpan\(`"(\w+\.\w+)`"\);", ""
+ $content = $content -creplace "\s+scope\.Start\(\);", ""
+ $content = $content -creplace "(?s)\s+try\s+\{\s+using PipelineMessage message = (?\w+)\((?[(\w+)(,\s\w+)]*)context\);\s+return Result\.FromResponse\(await _pipeline\.ProcessMessageAsync\(message, context\)\.ConfigureAwait\(false\)\);\s+\}", "`r`n options ??= new RequestOptions();`r`n using PipelineMessage message = `${method}(`${params}options);`r`n await _pipeline.SendAsync(message).ConfigureAwait(false);`r`n PipelineResponse response = message.Response!;`r`n`r`n if (response.IsError && options.ErrorOptions == ClientErrorBehaviors.Default)`r`n {`r`n throw await ClientResultException.CreateAsync(response).ConfigureAwait(false);`r`n }`r`n`r`n return ClientResult.FromResponse(response);"
+ $content = $content -creplace "(?s)\s+try\s+\{\s+using PipelineMessage message = (?\w+)\((?[(\w+)(,\s\w+)]*)context\);\s+return Result\.FromResponse\(_pipeline.ProcessMessage\(message, context\)\);\s+\}", "`r`n options ??= new RequestOptions();`r`n using PipelineMessage message = `${method}(`${params}options);`r`n _pipeline.Send(message);`r`n PipelineResponse response = message.Response!;`r`n`r`n if (response.IsError && options.ErrorOptions == ClientErrorBehaviors.Default)`r`n {`r`n throw new ClientResultException(response);`r`n }`r`n`r`n return ClientResult.FromResponse(response);"
+ $content = $content -creplace "(?s)\s+catch \(Exception e\)\s+\{\s+scope\.Failed\(e\);\s+throw;\s+\}", ""
+
+ # Create request
+ $content = $content -creplace "\(RequestBody content", "(BinaryContent content"
+ $content = $content -creplace " RequestBody content", " BinaryContent content"
+ $content = $content -creplace " RequestOptions context", " RequestOptions options"
+ $content = $content -creplace "var message = _pipeline\.CreateMessage\(context, ResponseErrorClassifier200\);", "PipelineMessage message = _pipeline.CreateMessage();`r`n message.ResponseClassifier = ResponseErrorClassifier200;"
+ $content = $content -creplace "var request = message\.Request;", "PipelineRequest request = message.Request;"
+ $content = $content -creplace "request\.SetMethod\(`"(?[\w\/]+)`"\);", "request.Method = `"`${name}`";"
+ $content = $content -creplace "var uri = new RequestUri\(\);", "UriBuilder uriBuilder = new(_endpoint.ToString());"
+ $content = $content -creplace "uri\.Reset\(_endpoint\);", "StringBuilder path = new();"
+ $content = $content -creplace "uri\.AppendPath\((?`"?[\w\/]+`"?), (\w+)\);", "path.Append(`${path});"
+ $content = $content -creplace "uri\.AppendQuery\(`"(?\w+)`", (?\w+(\.Value)?), (\w+)\);", "if (uriBuilder.Query != null && uriBuilder.Query.Length > 1)`r`n {`r`n uriBuilder.Query += $`"&`${key}={`${value}}`";`r`n }`r`n else`r`n {`r`n uriBuilder.Query = $`"`${key}={`${value}}`";`r`n }"
+ $content = $content -creplace "request\.Uri = uri\.ToUri\(\);", "uriBuilder.Path += path.ToString();`r`n request.Uri = uriBuilder.Uri;"
+ $content = $content -creplace "request\.SetHeaderValue", "request.Headers.Set"
+ $content = $content -creplace "request\.Content = content;", "request.Content = content;`r`n message.Apply(options);"
+
+ # Delete DefaultRequestContext
+ # $content = $content -creplace "\s+private static RequestOptions DefaultRequestContext = new RequestOptions\(\);", ""
+
+ # Clean up ApiKeyCredential
+ $content = $content -creplace " KeyCredential", " ApiKeyCredential"
+ $content = $content -creplace "_keyCredential", "_credential"
+ $content = $content -creplace " keyCredential", " credential"
+
+ # Clean up ClientPipeline
+ $content = $content -creplace " MessagePipeline ", " ClientPipeline "
+
+ # Clean up ClientResult
+ $content = $content -creplace " Result", " ClientResult"
+ $content = $content -creplace "Task _responseErrorClassifier200 \?\?= new StatusResponseClassifier\(stackalloc ushort\[\] \{ 200 \}\);", "private static PipelineMessageClassifier ResponseErrorClassifier200 => _responseErrorClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 });"
+
+ $content | Set-Content -Path $file.FullName -NoNewline
+ }
+}
+
+function Update-Models {
+ $root = Split-Path $PSScriptRoot -Parent
+ $directory = Join-Path -Path $root -ChildPath "src\Generated\Models"
+ $files = Get-ChildItem -Path $directory -Filter "*.cs"
+
+ foreach ($file in $files) {
+ $content = Get-Content -Path $file -Raw
+
+ Write-Output "Editing $($file.FullName)"
+
+ $content = $content -creplace "\s+#nullable disable", ""
+ $content = $content -creplace "ClientUtilities.AssertNotNull\((?@?\w+), nameof\((@?\w+)\)\);", "if (`${var} is null) throw new ArgumentNullException(nameof(`${var}));"
+ $content = $content -creplace "using System.ClientModel.Internal;", "using OpenAI.ClientShared.Internal;"
+ $content = $content -creplace ": IUtf8JsonWriteable,", ":"
+ $content = $content -creplace "\s+void IUtf8JsonWriteable\.Write\(Utf8JsonWriter writer\) => \(\(IJsonModel<(\w+)>\)this\)\.Write\(writer, new ModelReaderWriterOptions\(`"W`"\)\);`r`n", ""
+ $content = $content -creplace "(?s)\s+\/\/\/ Convert into a Utf8JsonRequestBody\. .*?return content;.*?\}", ""
+
+ $content | Set-Content -Path $file.FullName -NoNewline
+ }
+}
+
+function Update-Tests {
+ $root = Split-Path $PSScriptRoot -Parent
+ $directory = Join-Path -Path $root -ChildPath "tests\Generated\Tests"
+ $files = Get-ChildItem -Path $directory -Filter "*.cs"
+
+ foreach ($file in $files) {
+ $content = Get-Content -Path $file -Raw
+
+ Write-Output "Editing $($file.FullName)"
+
+ $content = $content -creplace " KeyCredential", " ApiKeyCredential"
+
+ $content | Set-Content -Path $file.FullName -NoNewline
+ }
+}
+
+Update-SystemClientModelPackage
+Update-OpenAIClient
+Update-OpenAIClientOptions
+Update-Subclients
+Update-Models
+Update-Tests
\ No newline at end of file
diff --git a/.dotnet/src/ClientShared/ModelReaderWriterExtensions.cs b/.dotnet/src/ClientShared/ModelReaderWriterExtensions.cs
new file mode 100644
index 000000000..25be6cbb5
--- /dev/null
+++ b/.dotnet/src/ClientShared/ModelReaderWriterExtensions.cs
@@ -0,0 +1,264 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#nullable enable
+
+using System;
+using System.ClientModel.Primitives;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using System.Text.Json;
+
+namespace OpenAI.ClientShared.Internal;
+
+internal static class ModelReaderWriterExtensions
+{
+ // TODO: These are copied from shared source files. If they become
+ // public we need to refactor and consolidate to a single place.
+
+ #region JsonElement
+
+ public static object? GetObject(in this JsonElement element)
+ {
+ switch (element.ValueKind)
+ {
+ case JsonValueKind.String:
+ return element.GetString();
+ case JsonValueKind.Number:
+ if (element.TryGetInt32(out int intValue))
+ {
+ return intValue;
+ }
+ if (element.TryGetInt64(out long longValue))
+ {
+ return longValue;
+ }
+ return element.GetDouble();
+ case JsonValueKind.True:
+ return true;
+ case JsonValueKind.False:
+ return false;
+ case JsonValueKind.Undefined:
+ case JsonValueKind.Null:
+ return null;
+ case JsonValueKind.Object:
+ var dictionary = new Dictionary();
+ foreach (JsonProperty jsonProperty in element.EnumerateObject())
+ {
+ dictionary.Add(jsonProperty.Name, jsonProperty.Value.GetObject());
+ }
+ return dictionary;
+ case JsonValueKind.Array:
+ var list = new List