diff --git a/tsp-output/@azure-tools/typespec-csharp/OpenAI.sln b/tsp-output/@azure-tools/typespec-csharp/OpenAI.sln index 5d1edd8c3..e46a7dedf 100644 --- a/tsp-output/@azure-tools/typespec-csharp/OpenAI.sln +++ b/tsp-output/@azure-tools/typespec-csharp/OpenAI.sln @@ -1,10 +1,16 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29709.97 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34701.34 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenAI", "src\OpenAI.csproj", "{28FF4005-4467-4E36-92E7-DEA27DEB1519}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenAI", "src\OpenAI.csproj", "{28FF4005-4467-4E36-92E7-DEA27DEB1519}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenAI.Tests", "tests\OpenAI.Tests.csproj", "{1F1CD1D4-9932-4B73-99D8-C252A67D4B46}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenAI.Tests", "tests\OpenAI.Tests.csproj", "{1F1CD1D4-9932-4B73-99D8-C252A67D4B46}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DemoApp", "app\DemoApp\DemoApp.csproj", "{79A5AD41-2A38-4771-93FE-0B3BCC6DB61A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AzureOpenAI", "azoai\AzureOpenAI\AzureOpenAI.csproj", "{FB61EB83-7171-48F4-9423-E64B99BDAA5A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.ClientModel", "..\..\..\..\azure-sdk-for-net\sdk\core\System.ClientModel\src\System.ClientModel.csproj", "{8364F37B-2B3D-4CAA-8F20-5B808E19C6CE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -12,26 +18,6 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B0C276D1-2930-4887-B29A-D1A33E7009A2}.Release|Any CPU.Build.0 = Release|Any CPU - {8E9A77AC-792A-4432-8320-ACFD46730401}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {8E9A77AC-792A-4432-8320-ACFD46730401}.Debug|Any CPU.Build.0 = Debug|Any CPU - {8E9A77AC-792A-4432-8320-ACFD46730401}.Release|Any CPU.ActiveCfg = Release|Any CPU - {8E9A77AC-792A-4432-8320-ACFD46730401}.Release|Any CPU.Build.0 = Release|Any CPU - {A4241C1F-A53D-474C-9E4E-075054407E74}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A4241C1F-A53D-474C-9E4E-075054407E74}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A4241C1F-A53D-474C-9E4E-075054407E74}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A4241C1F-A53D-474C-9E4E-075054407E74}.Release|Any CPU.Build.0 = Release|Any CPU - {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FA8BD3F1-8616-47B6-974C-7576CDF4717E}.Release|Any CPU.Build.0 = Release|Any CPU - {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {85677AD3-C214-42FA-AE6E-49B956CAC8DC}.Release|Any CPU.Build.0 = Release|Any CPU {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Debug|Any CPU.Build.0 = Debug|Any CPU {28FF4005-4467-4E36-92E7-DEA27DEB1519}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -40,6 +26,18 @@ Global {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Debug|Any CPU.Build.0 = Debug|Any CPU {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Release|Any CPU.ActiveCfg = Release|Any CPU {1F1CD1D4-9932-4B73-99D8-C252A67D4B46}.Release|Any CPU.Build.0 = Release|Any CPU + {79A5AD41-2A38-4771-93FE-0B3BCC6DB61A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79A5AD41-2A38-4771-93FE-0B3BCC6DB61A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79A5AD41-2A38-4771-93FE-0B3BCC6DB61A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79A5AD41-2A38-4771-93FE-0B3BCC6DB61A}.Release|Any CPU.Build.0 = Release|Any CPU + {FB61EB83-7171-48F4-9423-E64B99BDAA5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FB61EB83-7171-48F4-9423-E64B99BDAA5A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FB61EB83-7171-48F4-9423-E64B99BDAA5A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FB61EB83-7171-48F4-9423-E64B99BDAA5A}.Release|Any CPU.Build.0 = Release|Any CPU + {8364F37B-2B3D-4CAA-8F20-5B808E19C6CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8364F37B-2B3D-4CAA-8F20-5B808E19C6CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8364F37B-2B3D-4CAA-8F20-5B808E19C6CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8364F37B-2B3D-4CAA-8F20-5B808E19C6CE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/DemoApp.csproj b/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/DemoApp.csproj new file mode 100644 index 000000000..4e4604be7 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/DemoApp.csproj @@ -0,0 +1,16 @@ + + + + Exe + net6.0 + enable + enable + latest + + + + + + + + diff --git a/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/Mocks/MockPipelineTransport.cs b/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/Mocks/MockPipelineTransport.cs new file mode 100644 index 000000000..1258c9d8a --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/Mocks/MockPipelineTransport.cs @@ -0,0 +1,196 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel; +using System.ClientModel.Primitives; + +namespace ClientModel.Tests.Mocks; + +public class MockPipelineTransport : PipelineTransport +{ + private readonly Func _responseFactory; + private int _retryCount; + + public string Id { get; } + + public Action? OnSendingRequest { get; set; } + public Action? OnReceivedResponse { get; set; } + + public MockPipelineTransport(string id, params int[] codes) + : this(id, i => (codes[i], BinaryData.FromString(string.Empty))) + { + } + + public MockPipelineTransport(string id, Func responseFactory) + { + Id = id; + _responseFactory = responseFactory; + } + + protected override PipelineMessage CreateMessageCore() + { + return new RetriableTransportMessage(); + } + + protected override void ProcessCore(PipelineMessage message) + { + try + { + Stamp(message, "Transport"); + + OnSendingRequest?.Invoke(_retryCount, message); + + if (message is RetriableTransportMessage transportMessage) + { + (int status, BinaryData? content) = _responseFactory(_retryCount); + transportMessage.SetResponse(status, content); + } + + OnReceivedResponse?.Invoke(_retryCount, message); + } + finally + { + _retryCount++; + } + } + + protected override ValueTask ProcessCoreAsync(PipelineMessage message) + { + try + { + Stamp(message, "Transport"); + + OnSendingRequest?.Invoke(_retryCount, message); + + if (message is RetriableTransportMessage transportMessage) + { + (int status, BinaryData? content) = _responseFactory(_retryCount); + transportMessage.SetResponse(status, content); + } + + OnReceivedResponse?.Invoke(_retryCount, message); + } + finally + { + _retryCount++; + } + + return new ValueTask(); + } + + private void Stamp(PipelineMessage message, string prefix) + { + List values; + + if (message.TryGetProperty(typeof(ObservablePolicy), out object? prop) && + prop is List list) + { + values = list; + } + else + { + values = new List(); + message.SetProperty(typeof(ObservablePolicy), values); + } + + values.Add($"{prefix}:{Id}"); + } + + private class RetriableTransportMessage : PipelineMessage + { + public RetriableTransportMessage() : this(new TransportRequest()) + { + } + + protected internal RetriableTransportMessage(PipelineRequest request) : base(request) + { + } + + public void SetResponse(int status, BinaryData? content) + { + Response = new RetriableTransportResponse(status, content); + } + } + + private class TransportRequest : PipelineRequest + { + private Uri? _uri; + private readonly PipelineRequestHeaders _headers; + private string _method; + private BinaryContent? _content; + + public TransportRequest() + { + _headers = new MockRequestHeaders(); + _uri = new Uri("https://www.example.com"); + _method = "GET"; + } + + public override void Dispose() { } + + protected override BinaryContent? ContentCore + { + get => _content; + set => _content = value; + } + + protected override PipelineRequestHeaders HeadersCore + => _headers; + + protected override string MethodCore + { + get => _method; + set => _method = value; + } + + protected override Uri? UriCore + { + get => _uri; + set => _uri = value; + } + } + + private class RetriableTransportResponse : PipelineResponse + { + private Stream? _contentStream; + private BinaryData _content; + + public RetriableTransportResponse(int status, BinaryData? content) + { + Status = status; + ContentStream = content?.ToStream(); + _content = content ?? BinaryData.FromString(string.Empty); + } + + public override int Status { get; } + + public override string ReasonPhrase => throw new NotImplementedException(); + + public override Stream? ContentStream + { + get => _contentStream; + set => _contentStream = value; + } + + public override BinaryData Content => _content; + + protected override PipelineResponseHeaders HeadersCore + => throw new NotImplementedException(); + + public override void Dispose() { } + + public override BinaryData BufferContent(CancellationToken cancellationToken = default) + { + return _content = _contentStream == null ? + BinaryData.FromString(string.Empty) : + BinaryData.FromStream(_contentStream); + } + + public override ValueTask BufferContentAsync(CancellationToken cancellationToken = default) + { + return new(_content = _contentStream == null ? + BinaryData.FromString(string.Empty) : + BinaryData.FromStream(_contentStream)); + } + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/Mocks/MockRequestHeaders.cs b/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/Mocks/MockRequestHeaders.cs new file mode 100644 index 000000000..045e3a27e --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/Mocks/MockRequestHeaders.cs @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; + +namespace ClientModel.Tests.Mocks; + +public class MockRequestHeaders : PipelineRequestHeaders +{ + private readonly Dictionary _headers; + + public MockRequestHeaders() + { + _headers = new Dictionary(); + } + + public override void Add(string name, string value) + { + if (_headers.ContainsKey(name)) + { + _headers[name] += string.Concat(",", value); + } + else + { + _headers[name] = value; + } + } + + public override IEnumerator> GetEnumerator() + { + throw new NotImplementedException(); + } + + public override bool Remove(string name) + { + return _headers.Remove(name); + } + + public override void Set(string name, string value) + { + _headers[name] = value; + } + + public override bool TryGetValue(string name, out string? value) + { + return _headers.TryGetValue(name, out value); + } + + public override bool TryGetValues(string name, out IEnumerable? values) + { + throw new NotImplementedException(); + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/Mocks/ObservablePolicy.cs b/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/Mocks/ObservablePolicy.cs new file mode 100644 index 000000000..d70ea3b44 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/Mocks/ObservablePolicy.cs @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace ClientModel.Tests.Mocks; + +public class ObservablePolicy : PipelinePolicy +{ + public string Id { get; } + protected bool IsLastPolicy { get; set; } = false; + + public ObservablePolicy(string id) + { + Id = id; + } + + public override void Process(PipelineMessage message, IReadOnlyList pipeline, int currentIndex) + { + Stamp(message, "Request"); + + if (!IsLastPolicy) + { + ProcessNext(message, pipeline, currentIndex); + } + + Stamp(message, "Response"); + } + + public override async ValueTask ProcessAsync(PipelineMessage message, IReadOnlyList pipeline, int currentIndex) + { + Stamp(message, "Request"); + + if (!IsLastPolicy) + { + await ProcessNextAsync(message, pipeline, currentIndex).ConfigureAwait(false); + } + + Stamp(message, "Response"); + } + + private void Stamp(PipelineMessage message, string prefix) + { + List values; + + if (message.TryGetProperty(typeof(ObservablePolicy), out object? prop) && + prop is List list) + { + values = list; + } + else + { + values = new List(); + message.SetProperty(typeof(ObservablePolicy), values); + } + + values.Add($"{prefix}:{Id}"); + } + + public static List GetData(PipelineMessage message) + { + message.TryGetProperty(typeof(ObservablePolicy), out object? prop); + + return prop is List list ? list : new List(); + } + + public override string ToString() => $"ObservablePolicy:{Id}"; +} diff --git a/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/Program.cs b/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/Program.cs new file mode 100644 index 000000000..d71844c34 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/app/DemoApp/Program.cs @@ -0,0 +1,191 @@ +using AzureOpenAI; +using AzureOpenAI.Models; +using ClientModel.Tests.Mocks; +using OpenAI; +using OpenAI.Models; +using System.ClientModel; + +Console.WriteLine("Hello, World!"); + +//CallThirdPartyService(); +CallAzureService(); + +void CallThirdPartyService() +{ + // + string apiKey = Environment.GetEnvironmentVariable("OPENAI_KEY")!; + + OpenAIClient client = new(new Uri("https://www.mock-oai.com"), new ApiKeyCredential(apiKey), GetThirdPartyClientOptions()); + // + + Chat chatClient = client.GetChatClient(); + + List messages = new(); + var message = new + { + role = "user", + content = "running over the same old ground" + }; + messages.Add(BinaryData.FromObjectAsJson(message)); + + CreateChatCompletionRequest request = new(messages, CreateChatCompletionRequestModel.Gpt35Turbo); + + ClientResult result = chatClient.CreateChatCompletion(request); + CreateChatCompletionResponse completion = result.Value; + + // TODO: Do something with output +} + +void CallAzureService() +{ + // + Uri endpoint = new("https://annelo-openai-01.openai.azure.com/"); + string apiKey = "Fake"; // Environment.GetEnvironmentVariable("AZURE_OPENAI_KEY")!; + + AzureOpenAIClient client = new(endpoint, new ApiKeyCredential(apiKey), GetAzureClientOptions()); + // + + Chat chatClient = client.GetChatClient(); + + List messages = new(); + var message = new + { + role = "user", + content = "running over the same old ground" + }; + messages.Add(BinaryData.FromObjectAsJson(message)); + + CreateChatCompletionRequest request = new(messages, CreateChatCompletionRequestModel.Gpt35Turbo); + + // + + // Add Azure input property via extension methods + request.GetDataSources().Add(GetAzureSearchDataSource()); + + // + // request.DataSources.Add(GetAzureSearchDataSource()); + // + + // + + ClientResult result = chatClient.CreateChatCompletion(request); + + Console.WriteLine("**"); + + CreateChatCompletionResponse completion = result.Value; + + // + // Use Azure output property via extension methods + AzureChatExtensionsMessageContext? azureContext = completion.Choices[0].Message.GetAzureExtensionsContext(); + + if (azureContext is not null && azureContext.Citations.Count > 0) + { + int i = 0; + foreach (var citation in azureContext.Citations) + { + Console.WriteLine($"Citation {i++}: Content={citation.Content}, Uri={citation.Url}, Title={citation.Title}"); + } + } + // + + // TODO: illustrate calls to protocol method overloads. +} + +AzureSearchChatExtensionConfiguration GetAzureSearchDataSource() +{ + AzureSearchChatExtensionParameters searchParams = new(new Uri("https://azure.search.com"), "MySearchIndex"); + return new(searchParams); +} + +OpenAIClientOptions GetThirdPartyClientOptions() +{ + OpenAIClientOptions options = new() + { + Transport = new MockPipelineTransport("Transport", i => (200, BinaryData.FromString( + """ + { + "id": "chatcmpl-7R1nGnsXO8n4oi9UPz2f3UHdgAYMn", + "created": 1686676106, + "choices": [ + { + "index": 0, + "finish_reason": "stop", + "message": { + "role": "assistant", + "content": "Ahoy matey! So ye be wantin' to care for a fine squawkin' parrot, eh? Well, shiver me timbers, let ol' Cap'n Assistant share some wisdom with ye! Here be the steps to keepin' yer parrot happy 'n healthy:\n\n1. Secure a sturdy cage: Yer parrot be needin' a comfortable place to lay anchor! Be sure ye get a sturdy cage, at least double the size of the bird's wingspan, with enough space to spread their wings, yarrrr!\n\n2. Perches 'n toys: Aye, parrots need perches of different sizes, shapes, 'n textures to keep their feet healthy. Also, a few toys be helpin' to keep them entertained 'n their minds stimulated, arrrh!\n\n3. Proper grub: Feed yer feathered friend a balanced diet of high-quality pellets, fruits, 'n veggies to keep 'em strong 'n healthy. Give 'em fresh water every day, or ye’ll have a scurvy bird on yer hands!\n\n4. Cleanliness: Swab their cage deck! Clean their cage on a regular basis: fresh water 'n food daily, the floor every couple of days, 'n a thorough scrubbing ev'ry few weeks, so the bird be livin' in a tidy haven, arrhh!\n\n5. Socialize 'n train: Parrots be a sociable lot, arrr! Exercise 'n interact with 'em daily to create a bond 'n maintain their mental 'n physical health. Train 'em with positive reinforcement, treat 'em kindly, yarrr!\n\n6. Proper rest: Yer parrot be needin' ’bout 10-12 hours o' sleep each night. Cover their cage 'n let them slumber in a dim, quiet quarter for a proper night's rest, ye scallywag!\n\n7. Keep a weather eye open for illness: Birds be hidin' their ailments, arrr! Be watchful for signs of sickness, such as lethargy, loss of appetite, puffin' up, or change in droppings, and make haste to a vet if need be.\n\n8. Provide fresh air 'n avoid toxins: Parrots be sensitive to draft and pollutants. Keep yer quarters well ventilated, but no drafts, arrr! Be mindful of toxins like Teflon fumes, candles, or air fresheners.\n\nSo there ye have it, me hearty! With proper care 'n commitment, yer parrot will be squawkin' \"Yo-ho-ho\" for many years to come! Good luck, sailor, and may the wind be at yer back!" + }, + "logprobs": null + } + ], + "usage": { + "completion_tokens": 557, + "prompt_tokens": 33, + "total_tokens": 590 + } + } + """))) + }; + + return options; +} + + +AzureOpenAIClientOptions GetAzureClientOptions() +{ + MockPipelineTransport mockTransport = new("Transport", i => (200, BinaryData.FromString( + """ + { + "id": "chatcmpl-7R1nGnsXO8n4oi9UPz2f3UHdgAYMn", + "created": 1686676106, + "choices": [ + { + "index": 0, + "finish_reason": "stop", + "message": { + "role": "assistant", + "content": "Ahoy matey! So ye be wantin' to care for a fine squawkin' parrot, eh? Well, shiver me timbers, let ol' Cap'n Assistant share some wisdom with ye! Here be the steps to keepin' yer parrot happy 'n healthy:\n\n1. Secure a sturdy cage: Yer parrot be needin' a comfortable place to lay anchor! Be sure ye get a sturdy cage, at least double the size of the bird's wingspan, with enough space to spread their wings, yarrrr!\n\n2. Perches 'n toys: Aye, parrots need perches of different sizes, shapes, 'n textures to keep their feet healthy. Also, a few toys be helpin' to keep them entertained 'n their minds stimulated, arrrh!\n\n3. Proper grub: Feed yer feathered friend a balanced diet of high-quality pellets, fruits, 'n veggies to keep 'em strong 'n healthy. Give 'em fresh water every day, or ye’ll have a scurvy bird on yer hands!\n\n4. Cleanliness: Swab their cage deck! Clean their cage on a regular basis: fresh water 'n food daily, the floor every couple of days, 'n a thorough scrubbing ev'ry few weeks, so the bird be livin' in a tidy haven, arrhh!\n\n5. Socialize 'n train: Parrots be a sociable lot, arrr! Exercise 'n interact with 'em daily to create a bond 'n maintain their mental 'n physical health. Train 'em with positive reinforcement, treat 'em kindly, yarrr!\n\n6. Proper rest: Yer parrot be needin' ’bout 10-12 hours o' sleep each night. Cover their cage 'n let them slumber in a dim, quiet quarter for a proper night's rest, ye scallywag!\n\n7. Keep a weather eye open for illness: Birds be hidin' their ailments, arrr! Be watchful for signs of sickness, such as lethargy, loss of appetite, puffin' up, or change in droppings, and make haste to a vet if need be.\n\n8. Provide fresh air 'n avoid toxins: Parrots be sensitive to draft and pollutants. Keep yer quarters well ventilated, but no drafts, arrr! Be mindful of toxins like Teflon fumes, candles, or air fresheners.\n\nSo there ye have it, me hearty! With proper care 'n commitment, yer parrot will be squawkin' \"Yo-ho-ho\" for many years to come! Good luck, sailor, and may the wind be at yer back!", + "context": { + "citations": [ + { + "content": "Content of the citation", + "url": "https://www.example.com", + "title": "Title of the citation", + "filepath": "path/to/file", + "chunk_id": "chunk-id" + } + ] + } + }, + "logprobs": null + } + ], + "usage": { + "completion_tokens": 557, + "prompt_tokens": 33, + "total_tokens": 590 + } + } + """))); + + mockTransport.OnSendingRequest = (i, m) => + { + Console.WriteLine("Request:"); + Console.WriteLine($" Uri='{m.Request.Uri}'"); + Console.WriteLine($" Content='{WriteAsString(m.Request.Content!)}'"); + }; + + AzureOpenAIClientOptions options = new() + { + Transport = mockTransport + }; + + return options; +} + +string WriteAsString(BinaryContent content) +{ + MemoryStream stream = new(); + content.WriteTo(stream); + stream.Position = 0; + return BinaryData.FromStream(stream).ToString(); +} \ No newline at end of file diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/AzureChatClient.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/AzureChatClient.cs new file mode 100644 index 000000000..fe8ff22be --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/AzureChatClient.cs @@ -0,0 +1,107 @@ +using AzureOpenAI.Models; +using OpenAI; +using OpenAI.Models; +using System.ClientModel; +using System.ClientModel.Primitives; + +namespace AzureOpenAI; + +internal class AzureChatClient : Chat +{ + private readonly string _apiVersion; + private readonly Uri _endpoint; + + internal AzureChatClient(ClientPipeline pipeline, ApiKeyCredential credential, Uri endpoint, string apiVersion) + : base(pipeline, credential, endpoint) + { + _apiVersion = apiVersion; + _endpoint = endpoint; + } + + public override async Task> CreateChatCompletionAsync(CreateChatCompletionRequest createChatCompletionRequest, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(createChatCompletionRequest, nameof(createChatCompletionRequest)); + + using BinaryContent content = createChatCompletionRequest.ToBinaryContent(); + ClientResult result = await CreateChatCompletionAsync(createChatCompletionRequest.Model.ToString(), content, context: default).ConfigureAwait(false); + var value = ModelReaderWriter.Read(result.GetRawResponse().Content)!; + return ClientResult.FromValue(value, result.GetRawResponse()); + } + + public override ClientResult CreateChatCompletion(CreateChatCompletionRequest createChatCompletionRequest, CancellationToken cancellationToken = default) + { + Argument.AssertNotNull(createChatCompletionRequest, nameof(createChatCompletionRequest)); + + using BinaryContent content = createChatCompletionRequest.ToBinaryContent(); + ClientResult result = CreateChatCompletion(createChatCompletionRequest.Model.ToString(), content, context: default); + var value = ModelReaderWriter.Read(result.GetRawResponse().Content)!; + return ClientResult.FromValue(value, result.GetRawResponse()); + } + + public override Task CreateChatCompletionAsync(BinaryContent content, RequestOptions context = null) + { + // Note, that we can later remap the values from the 3rd party client format to the + // Azure client format, but this has a perf cost and it's an improvement that can + // come later. + throw new InvalidOperationException("Improperly formatted content -- Azure service requires different format. " + + $"Please consult the REST API documentation and call the '{nameof(CreateChatCompletion)}' method overload that " + + "takes a 'model' parameter."); + } + + public override ClientResult CreateChatCompletion(BinaryContent content, RequestOptions context = null) + { + throw new InvalidOperationException("Improperly formatted content -- Azure service requires different format. " + + $"Please consult the REST API documentation and call the '{nameof(CreateChatCompletion)}' method overload that " + + "takes a 'model' parameter."); + } + + public ClientResult CreateChatCompletion(string model, BinaryContent content, RequestOptions context = null) + { + Argument.AssertNotNull(model, nameof(model)); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateCreateChatCompletionRequest(model, content, context); + return ClientResult.FromResponse(Pipeline.ProcessMessage(message, context)); + } + + public async Task CreateChatCompletionAsync(string model, BinaryContent content, RequestOptions context = null) + { + Argument.AssertNotNull(model, nameof(model)); + Argument.AssertNotNull(content, nameof(content)); + + using PipelineMessage message = CreateCreateChatCompletionRequest(model, content, context); + return ClientResult.FromResponse(await Pipeline.ProcessMessageAsync(message, context).ConfigureAwait(false)); + } + + private PipelineMessage CreateCreateChatCompletionRequest(string model, BinaryContent content, RequestOptions context) + { + var message = Pipeline.CreateMessage(); + message.ResponseClassifier = PipelineMessageClassifier200; + + var request = message.Request; + request.Method = "POST"; + + var uri = new ClientUriBuilder(); + uri.Reset(_endpoint); + uri.AppendPath("/openai/deployments/", false); + uri.AppendPath(model, false); + uri.AppendPath("/chat/completions", false); + uri.AppendQuery("api-version", _apiVersion, true); + request.Uri = uri.ToUri(); + + request.Headers.Set("Accept", "application/json"); + request.Headers.Set("Content-Type", "application/json"); + + request.Content = content; + + if (context != null) + { + message.Apply(context); + } + + return message; + } + + private static PipelineMessageClassifier? _pipelineMessageClassifier200; + private static PipelineMessageClassifier PipelineMessageClassifier200 => _pipelineMessageClassifier200 ??= PipelineMessageClassifier.Create(stackalloc ushort[] { 200 }); +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/AzureOpenAI.csproj b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/AzureOpenAI.csproj new file mode 100644 index 000000000..460feb8c7 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/AzureOpenAI.csproj @@ -0,0 +1,14 @@ + + + + netstandard2.0 + enable + enable + latest + + + + + + + diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/AzureOpenAIClient.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/AzureOpenAIClient.cs new file mode 100644 index 000000000..81ea55bb2 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/AzureOpenAIClient.cs @@ -0,0 +1,26 @@ +using OpenAI; +using System.ClientModel; + +namespace AzureOpenAI; + +public class AzureOpenAIClient : OpenAIClient +{ + private readonly string _apiVersion; + private readonly ApiKeyCredential _apiKeyCredential; + private readonly Uri _endpoint; + + public AzureOpenAIClient(Uri endpoint, ApiKeyCredential credential, AzureOpenAIClientOptions? options = default) + : base(endpoint, credential, options) + { + options ??= new AzureOpenAIClientOptions(); + + _apiVersion = options.ApiVersion; + _endpoint = endpoint; + _apiKeyCredential = credential; + } + + public override Chat GetChatClient() + { + return new AzureChatClient(Pipeline, _apiKeyCredential, _endpoint, _apiVersion); + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/AzureOpenAIClientOptions.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/AzureOpenAIClientOptions.cs new file mode 100644 index 000000000..23cc45ae3 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/AzureOpenAIClientOptions.cs @@ -0,0 +1,13 @@ +using OpenAI; + +namespace AzureOpenAI; + +public class AzureOpenAIClientOptions : OpenAIClientOptions +{ + public AzureOpenAIClientOptions(string? version = default) + { + ApiVersion = version ?? "1.0"; + } + + public string ApiVersion { get; set; } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/ChatClientExtensions.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/ChatClientExtensions.cs new file mode 100644 index 000000000..0bef56f06 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/ChatClientExtensions.cs @@ -0,0 +1,29 @@ +using OpenAI; +using System.ClientModel; +using System.ClientModel.Primitives; + +namespace AzureOpenAI; + +public static class ChatClientExtensions +{ + // Expose overloads of protocol methods as extensions to the base client + public static ClientResult CreateChatCompletion(this Chat client, string model, BinaryContent content, RequestOptions options = default) + { + if (client is not AzureChatClient azureClient) + { + throw new NotSupportedException("Cannot call CreateChatCompletion with 'model' parameter when not using the Azure OpeAI client."); + } + + return azureClient.CreateChatCompletion(model, content, options); + } + + public static async Task CreateChatCompletionAsync(this Chat client, string model, BinaryContent content, RequestOptions options = default) + { + if (client is not AzureChatClient azureClient) + { + throw new NotSupportedException("Cannot call CreateChatCompletionAsync with 'model' parameter when not using the Azure OpeAI client."); + } + + return await azureClient.CreateChatCompletionAsync(model, content, options).ConfigureAwait(false); + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/Argument.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/Argument.cs new file mode 100644 index 000000000..b39f2be32 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/Argument.cs @@ -0,0 +1,125 @@ +// + +#nullable disable + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace AzureOpenAI; + +internal static class Argument +{ + public static void AssertNotNull(T value, string name) + { + if (value is null) + { + throw new ArgumentNullException(name); + } + } + + public static void AssertNotNull(T? value, string name) + where T : struct + { + if (!value.HasValue) + { + throw new ArgumentNullException(name); + } + } + + public static void AssertNotNullOrEmpty(IEnumerable value, string name) + { + if (value is null) + { + throw new ArgumentNullException(name); + } + if (value is ICollection collectionOfT && collectionOfT.Count == 0) + { + throw new ArgumentException("Value cannot be an empty collection.", name); + } + if (value is ICollection collection && collection.Count == 0) + { + throw new ArgumentException("Value cannot be an empty collection.", name); + } + using IEnumerator e = value.GetEnumerator(); + if (!e.MoveNext()) + { + throw new ArgumentException("Value cannot be an empty collection.", name); + } + } + + public static void AssertNotNullOrEmpty(string value, string name) + { + if (value is null) + { + throw new ArgumentNullException(name); + } + if (value.Length == 0) + { + throw new ArgumentException("Value cannot be an empty string.", name); + } + } + + public static void AssertNotNullOrWhiteSpace(string value, string name) + { + if (value is null) + { + throw new ArgumentNullException(name); + } + if (string.IsNullOrWhiteSpace(value)) + { + throw new ArgumentException("Value cannot be empty or contain only white-space characters.", name); + } + } + + public static void AssertNotDefault(ref T value, string name) + where T : struct, IEquatable + { + if (value.Equals(default)) + { + throw new ArgumentException("Value cannot be empty.", name); + } + } + + public static void AssertInRange(T value, T minimum, T maximum, string name) + where T : notnull, IComparable + { + if (minimum.CompareTo(value) > 0) + { + throw new ArgumentOutOfRangeException(name, "Value is less than the minimum allowed."); + } + if (maximum.CompareTo(value) < 0) + { + throw new ArgumentOutOfRangeException(name, "Value is greater than the maximum allowed."); + } + } + + public static void AssertEnumDefined(Type enumType, object value, string name) + { + if (!Enum.IsDefined(enumType, value)) + { + throw new ArgumentException($"Value not defined for {enumType.FullName}.", name); + } + } + + public static T CheckNotNull(T value, string name) + where T : class + { + AssertNotNull(value, name); + return value; + } + + public static string CheckNotNullOrEmpty(string value, string name) + { + AssertNotNullOrEmpty(value, name); + return value; + } + + public static void AssertNull(T value, string name, string message = null) + { + if (value != null) + { + throw new ArgumentException(message ?? "Value must be null.", name); + } + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ChangeTrackingDictionary.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ChangeTrackingDictionary.cs new file mode 100644 index 000000000..b054e615b --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ChangeTrackingDictionary.cs @@ -0,0 +1,163 @@ +// + +#nullable disable + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace AzureOpenAI; + +internal class ChangeTrackingDictionary : IDictionary, IReadOnlyDictionary where TKey : notnull +{ + private IDictionary _innerDictionary; + + public ChangeTrackingDictionary() + { + } + + public ChangeTrackingDictionary(IDictionary dictionary) + { + if (dictionary == null) + { + return; + } + _innerDictionary = new Dictionary(dictionary); + } + + public ChangeTrackingDictionary(IReadOnlyDictionary dictionary) + { + if (dictionary == null) + { + return; + } + _innerDictionary = new Dictionary(); + foreach (var pair in dictionary) + { + _innerDictionary.Add(pair); + } + } + + public bool IsUndefined => _innerDictionary == null; + + public int Count => IsUndefined ? 0 : EnsureDictionary().Count; + + public bool IsReadOnly => IsUndefined ? false : EnsureDictionary().IsReadOnly; + + public ICollection Keys => IsUndefined ? Array.Empty() : EnsureDictionary().Keys; + + public ICollection Values => IsUndefined ? Array.Empty() : EnsureDictionary().Values; + + public TValue this[TKey key] + { + get + { + if (IsUndefined) + { + throw new KeyNotFoundException(nameof(key)); + } + return EnsureDictionary()[key]; + } + set + { + EnsureDictionary()[key] = value; + } + } + + IEnumerable IReadOnlyDictionary.Keys => Keys; + + IEnumerable IReadOnlyDictionary.Values => Values; + + public IEnumerator> GetEnumerator() + { + if (IsUndefined) + { + IEnumerator> enumerateEmpty() + { + yield break; + } + return enumerateEmpty(); + } + return EnsureDictionary().GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(KeyValuePair item) + { + EnsureDictionary().Add(item); + } + + public void Clear() + { + EnsureDictionary().Clear(); + } + + public bool Contains(KeyValuePair item) + { + if (IsUndefined) + { + return false; + } + return EnsureDictionary().Contains(item); + } + + public void CopyTo(KeyValuePair[] array, int index) + { + if (IsUndefined) + { + return; + } + EnsureDictionary().CopyTo(array, index); + } + + public bool Remove(KeyValuePair item) + { + if (IsUndefined) + { + return false; + } + return EnsureDictionary().Remove(item); + } + + public void Add(TKey key, TValue value) + { + EnsureDictionary().Add(key, value); + } + + public bool ContainsKey(TKey key) + { + if (IsUndefined) + { + return false; + } + return EnsureDictionary().ContainsKey(key); + } + + public bool Remove(TKey key) + { + if (IsUndefined) + { + return false; + } + return EnsureDictionary().Remove(key); + } + + public bool TryGetValue(TKey key, out TValue value) + { + if (IsUndefined) + { + value = default; + return false; + } + return EnsureDictionary().TryGetValue(key, out value); + } + + public IDictionary EnsureDictionary() + { + return _innerDictionary ??= new Dictionary(); + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ChangeTrackingList.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ChangeTrackingList.cs new file mode 100644 index 000000000..a2ff13738 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ChangeTrackingList.cs @@ -0,0 +1,149 @@ +// + +#nullable disable + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + +namespace AzureOpenAI; + +internal class ChangeTrackingList : IList, IReadOnlyList +{ + private IList _innerList; + + public ChangeTrackingList() + { + } + + public ChangeTrackingList(IList innerList) + { + if (innerList != null) + { + _innerList = innerList; + } + } + + public ChangeTrackingList(IReadOnlyList innerList) + { + if (innerList != null) + { + _innerList = innerList.ToList(); + } + } + + public bool IsUndefined => _innerList == null; + + public int Count => IsUndefined ? 0 : EnsureList().Count; + + public bool IsReadOnly => IsUndefined ? false : EnsureList().IsReadOnly; + + public T this[int index] + { + get + { + if (IsUndefined) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + return EnsureList()[index]; + } + set + { + if (IsUndefined) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + EnsureList()[index] = value; + } + } + + public void Reset() + { + _innerList = null; + } + + public IEnumerator GetEnumerator() + { + if (IsUndefined) + { + IEnumerator enumerateEmpty() + { + yield break; + } + return enumerateEmpty(); + } + return EnsureList().GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(T item) + { + EnsureList().Add(item); + } + + public void Clear() + { + EnsureList().Clear(); + } + + public bool Contains(T item) + { + if (IsUndefined) + { + return false; + } + return EnsureList().Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + if (IsUndefined) + { + return; + } + EnsureList().CopyTo(array, arrayIndex); + } + + public bool Remove(T item) + { + if (IsUndefined) + { + return false; + } + return EnsureList().Remove(item); + } + + public int IndexOf(T item) + { + if (IsUndefined) + { + return -1; + } + return EnsureList().IndexOf(item); + } + + public void Insert(int index, T item) + { + EnsureList().Insert(index, item); + } + + public void RemoveAt(int index) + { + if (IsUndefined) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + EnsureList().RemoveAt(index); + } + + public IList EnsureList() + { + return _innerList ??= new List(); + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ClientPipelineExtensions.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ClientPipelineExtensions.cs new file mode 100644 index 000000000..356acda94 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ClientPipelineExtensions.cs @@ -0,0 +1,49 @@ +// + +#nullable disable + +using System; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Threading; +using System.Threading.Tasks; + +namespace OpenAI +{ + internal static class ClientPipelineExtensions + { + public static async ValueTask ProcessMessageAsync(this ClientPipeline pipeline, PipelineMessage message, RequestOptions requestContext, CancellationToken cancellationToken = default) + { + await pipeline.SendAsync(message).ConfigureAwait(false); + + if (message.Response == null) + { + throw new InvalidOperationException("Failed to receive Result."); + } + + if (!message.Response.IsError || requestContext?.ErrorOptions == ClientErrorBehaviors.NoThrow) + { + return message.Response; + } + + throw new ClientResultException(message.Response); + } + + public static PipelineResponse ProcessMessage(this ClientPipeline pipeline, PipelineMessage message, RequestOptions requestContext, CancellationToken cancellationToken = default) + { + pipeline.Send(message); + + if (message.Response == null) + { + throw new InvalidOperationException("Failed to receive Result."); + } + + if (!message.Response.IsError || requestContext?.ErrorOptions == ClientErrorBehaviors.NoThrow) + { + return message.Response; + } + + throw new ClientResultException(message.Response); + } + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ClientUriBuilder.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ClientUriBuilder.cs new file mode 100644 index 000000000..782d0be04 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ClientUriBuilder.cs @@ -0,0 +1,209 @@ +// + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AzureOpenAI; + +internal class ClientUriBuilder +{ + private UriBuilder _uriBuilder; + private StringBuilder _pathBuilder; + private StringBuilder _queryBuilder; + private const char PathSeparator = '/'; + + public ClientUriBuilder() + { + } + + private UriBuilder UriBuilder => _uriBuilder ??= new UriBuilder(); + + private StringBuilder PathBuilder => _pathBuilder ??= new StringBuilder(UriBuilder.Path); + + private StringBuilder QueryBuilder => _queryBuilder ??= new StringBuilder(UriBuilder.Query); + + public void Reset(Uri uri) + { + _uriBuilder = new UriBuilder(uri); + _pathBuilder = new StringBuilder(UriBuilder.Path); + _queryBuilder = new StringBuilder(UriBuilder.Query); + } + + public void AppendPath(string value, bool escape) + { + Argument.AssertNotNullOrWhiteSpace(value, nameof(value)); + + if (escape) + { + value = Uri.EscapeDataString(value); + } + + if (value[0] == PathSeparator) + { + value = value.Substring(1); + } + + PathBuilder.Append(value); + UriBuilder.Path = PathBuilder.ToString(); + } + + public void AppendPath(bool value, bool escape = false) + { + AppendPath(ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendPath(float value, bool escape = true) + { + AppendPath(ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendPath(double value, bool escape = true) + { + AppendPath(ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendPath(int value, bool escape = true) + { + AppendPath(ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendPath(byte[] value, string format, bool escape = true) + { + AppendPath(ModelSerializationExtensions.TypeFormatters.ConvertToString(value, format), escape); + } + + public void AppendPath(IEnumerable value, bool escape = true) + { + AppendPath(ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendPath(DateTimeOffset value, string format, bool escape = true) + { + AppendPath(ModelSerializationExtensions.TypeFormatters.ConvertToString(value, format), escape); + } + + public void AppendPath(TimeSpan value, string format, bool escape = true) + { + AppendPath(ModelSerializationExtensions.TypeFormatters.ConvertToString(value, format), escape); + } + + public void AppendPath(Guid value, bool escape = true) + { + AppendPath(ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendPath(long value, bool escape = true) + { + AppendPath(ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendQuery(string name, string value, bool escape) + { + Argument.AssertNotNullOrWhiteSpace(name, nameof(name)); + Argument.AssertNotNullOrWhiteSpace(value, nameof(value)); + + if (QueryBuilder.Length == 0) + { + QueryBuilder.Append('?'); + } + else + { + QueryBuilder.Append('&'); + } + + if (escape) + { + value = Uri.EscapeDataString(value); + } + + QueryBuilder.Append(name); + QueryBuilder.Append('='); + QueryBuilder.Append(value); + } + + public void AppendQuery(string name, bool value, bool escape = false) + { + AppendQuery(name, ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendQuery(string name, float value, bool escape = true) + { + AppendQuery(name, ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendQuery(string name, DateTimeOffset value, string format, bool escape = true) + { + AppendQuery(name, ModelSerializationExtensions.TypeFormatters.ConvertToString(value, format), escape); + } + + public void AppendQuery(string name, TimeSpan value, string format, bool escape = true) + { + AppendQuery(name, ModelSerializationExtensions.TypeFormatters.ConvertToString(value, format), escape); + } + + public void AppendQuery(string name, double value, bool escape = true) + { + AppendQuery(name, ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendQuery(string name, decimal value, bool escape = true) + { + AppendQuery(name, ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendQuery(string name, int value, bool escape = true) + { + AppendQuery(name, ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendQuery(string name, long value, bool escape = true) + { + AppendQuery(name, ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendQuery(string name, TimeSpan value, bool escape = true) + { + AppendQuery(name, ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendQuery(string name, byte[] value, string format, bool escape = true) + { + AppendQuery(name, ModelSerializationExtensions.TypeFormatters.ConvertToString(value, format), escape); + } + + public void AppendQuery(string name, Guid value, bool escape = true) + { + AppendQuery(name, ModelSerializationExtensions.TypeFormatters.ConvertToString(value), escape); + } + + public void AppendQueryDelimited(string name, IEnumerable value, string delimiter, bool escape = true) + { + var stringValues = value.Select(v => ModelSerializationExtensions.TypeFormatters.ConvertToString(v)); + AppendQuery(name, string.Join(delimiter, stringValues), escape); + } + + public void AppendQueryDelimited(string name, IEnumerable value, string delimiter, string format, bool escape = true) + { + var stringValues = value.Select(v => ModelSerializationExtensions.TypeFormatters.ConvertToString(v, format)); + AppendQuery(name, string.Join(delimiter, stringValues), escape); + } + + public Uri ToUri() + { + if (_pathBuilder != null) + { + UriBuilder.Path = _pathBuilder.ToString(); + } + + if (_queryBuilder != null) + { + UriBuilder.Query = _queryBuilder.ToString(); + } + + return UriBuilder.Uri; + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/JsonModelList.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/JsonModelList.cs new file mode 100644 index 000000000..eac0fd6c8 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/JsonModelList.cs @@ -0,0 +1,89 @@ +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace AzureOpenAI; + +internal class JsonModelList : List, IJsonModel> + where TModel : IJsonModel +{ + public JsonModelList Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel>)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(JsonModelList)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeJsonModelList(document.RootElement, options); + } + + public JsonModelList Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel>)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeJsonModelList(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(JsonModelList)} does not support reading '{options.Format}' format."); + } + } + + internal static JsonModelList DeserializeJsonModelList(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= new ModelReaderWriterOptions("W"); + + if (element.ValueKind != JsonValueKind.Array) + { + throw new InvalidOperationException("Cannot deserialize JsonModelList from JSON that is not an array."); + } + + JsonModelList list = []; + + foreach (JsonElement item in element.EnumerateArray()) + { + // TODO: Make efficient + TModel? value = ModelReaderWriter.Read(BinaryData.FromString(item.ToString()), options) ?? + throw new InvalidOperationException("Failed to deserialized array element."); + list.Add(value); + } + + return list; + } + + public string GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + public void Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel>)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(JsonModelList)} does not support writing '{format}' format."); + } + + writer.WriteStartArray(); + + foreach (IJsonModel item in this) + { + item.Write(writer, options); + } + + writer.WriteEndArray(); + } + + public BinaryData Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel>)this).GetFormatFromOptions(options) : options.Format; + + return format switch + { + "J" => ModelReaderWriter.Write(this, options), + _ => throw new FormatException($"The model {nameof(JsonModelList)} does not support writing '{options.Format}' format."), + }; + } +} \ No newline at end of file diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ModelSerializationExtensions.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ModelSerializationExtensions.cs new file mode 100644 index 000000000..e4edf1684 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/ModelSerializationExtensions.cs @@ -0,0 +1,388 @@ +// + +#nullable disable + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Text.Json; +using System.Xml; + +namespace AzureOpenAI; + +internal static class ModelSerializationExtensions +{ + public static object GetObject(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 (var jsonProperty in element.EnumerateObject()) + { + dictionary.Add(jsonProperty.Name, jsonProperty.Value.GetObject()); + } + return dictionary; + case JsonValueKind.Array: + var list = new List(); + foreach (var item in element.EnumerateArray()) + { + list.Add(item.GetObject()); + } + return list.ToArray(); + default: + throw new NotSupportedException($"Not supported value kind {element.ValueKind}"); + } + } + + public static byte[] GetBytesFromBase64(this JsonElement element, string format) + { + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + + return format switch + { + "U" => TypeFormatters.FromBase64UrlString(element.GetRequiredString()), + "D" => element.GetBytesFromBase64(), + _ => throw new ArgumentException($"Format is not supported: '{format}'", nameof(format)) + }; + } + + public static DateTimeOffset GetDateTimeOffset(this JsonElement element, string format) => format switch + { + "U" when element.ValueKind == JsonValueKind.Number => DateTimeOffset.FromUnixTimeSeconds(element.GetInt64()), + _ => TypeFormatters.ParseDateTimeOffset(element.GetString(), format) + }; + + public static TimeSpan GetTimeSpan(this JsonElement element, string format) => TypeFormatters.ParseTimeSpan(element.GetString(), format); + + public static char GetChar(this JsonElement element) + { + if (element.ValueKind == JsonValueKind.String) + { + var text = element.GetString(); + if (text == null || text.Length != 1) + { + throw new NotSupportedException($"Cannot convert \"{text}\" to a char"); + } + return text[0]; + } + else + { + throw new NotSupportedException($"Cannot convert {element.ValueKind} to a char"); + } + } + + [Conditional("DEBUG")] + public static void ThrowNonNullablePropertyIsNull(this JsonProperty property) + { + throw new JsonException($"A property '{property.Name}' defined as non-nullable but received as null from the service. This exception only happens in DEBUG builds of the library and would be ignored in the release build"); + } + + public static string GetRequiredString(this JsonElement element) + { + var value = element.GetString(); + if (value == null) + { + throw new InvalidOperationException($"The requested operation requires an element of type 'String', but the target element has type '{element.ValueKind}'."); + } + return value; + } + + public static void WriteStringValue(this Utf8JsonWriter writer, DateTimeOffset value, string format) + { + writer.WriteStringValue(TypeFormatters.ToString(value, format)); + } + + public static void WriteStringValue(this Utf8JsonWriter writer, DateTime value, string format) + { + writer.WriteStringValue(TypeFormatters.ToString(value, format)); + } + + public static void WriteStringValue(this Utf8JsonWriter writer, TimeSpan value, string format) + { + writer.WriteStringValue(TypeFormatters.ToString(value, format)); + } + + public static void WriteStringValue(this Utf8JsonWriter writer, char value) + { + writer.WriteStringValue(value.ToString(CultureInfo.InvariantCulture)); + } + + public static void WriteBase64StringValue(this Utf8JsonWriter writer, byte[] value, string format) + { + if (value == null) + { + writer.WriteNullValue(); + return; + } + switch (format) + { + case "U": + writer.WriteStringValue(TypeFormatters.ToBase64UrlString(value)); + break; + case "D": + writer.WriteBase64StringValue(value); + break; + default: + throw new ArgumentException($"Format is not supported: '{format}'", nameof(format)); + } + } + + public static void WriteNumberValue(this Utf8JsonWriter writer, DateTimeOffset value, string format) + { + if (format != "U") + { + throw new ArgumentOutOfRangeException(nameof(format), "Only 'U' format is supported when writing a DateTimeOffset as a Number."); + } + writer.WriteNumberValue(value.ToUnixTimeSeconds()); + } + + public static void WriteObjectValue(this Utf8JsonWriter writer, object value, ModelReaderWriterOptions options = null) + { + switch (value) + { + case null: + writer.WriteNullValue(); + break; + case IJsonModel jsonModel: + jsonModel.Write(writer, options ?? new ModelReaderWriterOptions("W")); + break; + case byte[] bytes: + writer.WriteBase64StringValue(bytes); + break; + case BinaryData bytes0: + writer.WriteBase64StringValue(bytes0); + break; + case JsonElement json: + json.WriteTo(writer); + break; + case int i: + writer.WriteNumberValue(i); + break; + case decimal d: + writer.WriteNumberValue(d); + break; + case double d0: + if (double.IsNaN(d0)) + { + writer.WriteStringValue("NaN"); + } + else + { + writer.WriteNumberValue(d0); + } + break; + case float f: + writer.WriteNumberValue(f); + break; + case long l: + writer.WriteNumberValue(l); + break; + case string s: + writer.WriteStringValue(s); + break; + case bool b: + writer.WriteBooleanValue(b); + break; + case Guid g: + writer.WriteStringValue(g); + break; + case DateTimeOffset dateTimeOffset: + writer.WriteStringValue(dateTimeOffset, "O"); + break; + case DateTime dateTime: + writer.WriteStringValue(dateTime, "O"); + break; + case IEnumerable> enumerable: + writer.WriteStartObject(); + foreach (var pair in enumerable) + { + writer.WritePropertyName(pair.Key); + writer.WriteObjectValue(pair.Value, options); + } + writer.WriteEndObject(); + break; + case IEnumerable objectEnumerable: + writer.WriteStartArray(); + foreach (var item in objectEnumerable) + { + writer.WriteObjectValue(item, options); + } + writer.WriteEndArray(); + break; + case TimeSpan timeSpan: + writer.WriteStringValue(timeSpan, "P"); + break; + default: + throw new NotSupportedException($"Not supported type {value.GetType()}"); + } + } + + public static void WriteObjectValue(this Utf8JsonWriter writer, object value, ModelReaderWriterOptions options = null) + { + writer.WriteObjectValue(value, options); + } + + internal static class TypeFormatters + { + private const string RoundtripZFormat = "yyyy-MM-ddTHH:mm:ss.fffffffZ"; + public const string DefaultNumberFormat = "G"; + + public static string ToString(bool value) => value ? "true" : "false"; + + public static string ToString(DateTime value, string format) => value.Kind switch + { + DateTimeKind.Utc => ToString((DateTimeOffset)value, format), + _ => throw new NotSupportedException($"DateTime {value} has a Kind of {value.Kind}. Azure SDK requires it to be UTC. You can call DateTime.SpecifyKind to change Kind property value to DateTimeKind.Utc.") + }; + + public static string ToString(DateTimeOffset value, string format) => format switch + { + "D" => value.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture), + "U" => value.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture), + "O" => value.ToUniversalTime().ToString(RoundtripZFormat, CultureInfo.InvariantCulture), + "o" => value.ToUniversalTime().ToString(RoundtripZFormat, CultureInfo.InvariantCulture), + "R" => value.ToString("r", CultureInfo.InvariantCulture), + _ => value.ToString(format, CultureInfo.InvariantCulture) + }; + + public static string ToString(TimeSpan value, string format) => format switch + { + "P" => XmlConvert.ToString(value), + _ => value.ToString(format, CultureInfo.InvariantCulture) + }; + + public static string ToString(byte[] value, string format) => format switch + { + "U" => ToBase64UrlString(value), + "D" => Convert.ToBase64String(value), + _ => throw new ArgumentException($"Format is not supported: '{format}'", nameof(format)) + }; + + public static string ToBase64UrlString(byte[] value) + { + int numWholeOrPartialInputBlocks = checked(value.Length + 2) / 3; + int size = checked(numWholeOrPartialInputBlocks * 4); + char[] output = new char[size]; + + int numBase64Chars = Convert.ToBase64CharArray(value, 0, value.Length, output, 0); + + int i = 0; + for (; i < numBase64Chars; i++) + { + char ch = output[i]; + if (ch == '+') + { + output[i] = '-'; + } + else + { + if (ch == '/') + { + output[i] = '_'; + } + else + { + if (ch == '=') + { + break; + } + } + } + } + + return new string(output, 0, i); + } + + public static byte[] FromBase64UrlString(string value) + { + int paddingCharsToAdd = (value.Length % 4) switch + { + 0 => 0, + 2 => 2, + 3 => 1, + _ => throw new InvalidOperationException("Malformed input") + }; + char[] output = new char[(value.Length + paddingCharsToAdd)]; + int i = 0; + for (; i < value.Length; i++) + { + char ch = value[i]; + if (ch == '-') + { + output[i] = '+'; + } + else + { + if (ch == '_') + { + output[i] = '/'; + } + else + { + output[i] = ch; + } + } + } + + for (; i < output.Length; i++) + { + output[i] = '='; + } + + return Convert.FromBase64CharArray(output, 0, output.Length); + } + + public static DateTimeOffset ParseDateTimeOffset(string value, string format) => format switch + { + "U" => DateTimeOffset.FromUnixTimeSeconds(long.Parse(value, CultureInfo.InvariantCulture)), + _ => DateTimeOffset.Parse(value, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal) + }; + + public static TimeSpan ParseTimeSpan(string value, string format) => format switch + { + "P" => XmlConvert.ToTimeSpan(value), + _ => TimeSpan.ParseExact(value, format, CultureInfo.InvariantCulture) + }; + + public static string ConvertToString(object value, string format = null) => value switch + { + null => "null", + string s => s, + bool b => ToString(b), + int or float or double or long or decimal => ((IFormattable)value).ToString(DefaultNumberFormat, CultureInfo.InvariantCulture), + byte[] b0 when format != null => ToString(b0, format), + IEnumerable s0 => string.Join(",", s0), + DateTimeOffset dateTime when format != null => ToString(dateTime, format), + TimeSpan timeSpan when format != null => ToString(timeSpan, format), + TimeSpan timeSpan0 => XmlConvert.ToString(timeSpan0), + Guid guid => guid.ToString(), + BinaryData binaryData => ConvertToString(binaryData.ToArray(), format), + _ => value.ToString() + }; + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/Optional.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/Optional.cs new file mode 100644 index 000000000..465c25d9c --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Generated/Internal/Optional.cs @@ -0,0 +1,47 @@ +// + +#nullable disable + +using System.Collections.Generic; +using System.Text.Json; + +namespace AzureOpenAI; + +internal static class Optional +{ + public static bool IsCollectionDefined(IEnumerable collection) + { + return !(collection is ChangeTrackingList changeTrackingList && changeTrackingList.IsUndefined); + } + + public static bool IsCollectionDefined(IDictionary collection) + { + return !(collection is ChangeTrackingDictionary changeTrackingDictionary && changeTrackingDictionary.IsUndefined); + } + + public static bool IsCollectionDefined(IReadOnlyDictionary collection) + { + return !(collection is ChangeTrackingDictionary changeTrackingDictionary && changeTrackingDictionary.IsUndefined); + } + + public static bool IsDefined(T? value) + where T : struct + { + return value.HasValue; + } + + public static bool IsDefined(object value) + { + return value != null; + } + + public static bool IsDefined(JsonElement value) + { + return value.ValueKind != JsonValueKind.Undefined; + } + + public static bool IsDefined(string value) + { + return value != null; + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureChatExtensionConfiguration.Serialization.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureChatExtensionConfiguration.Serialization.cs new file mode 100644 index 000000000..ad595cb27 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureChatExtensionConfiguration.Serialization.cs @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace AzureOpenAI.Models; + +[PersistableModelProxy(typeof(UnknownAzureChatExtensionConfiguration))] +public partial class AzureChatExtensionConfiguration : IJsonModel +{ + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(AzureChatExtensionConfiguration)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + writer.WritePropertyName("type"u8); + writer.WriteStringValue(Type.ToString()); + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + 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 + } + } + writer.WriteEndObject(); + } + + AzureChatExtensionConfiguration IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(AzureChatExtensionConfiguration)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeAzureChatExtensionConfiguration(document.RootElement, options); + } + + internal static AzureChatExtensionConfiguration DeserializeAzureChatExtensionConfiguration(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= new ModelReaderWriterOptions("W"); + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + if (element.TryGetProperty("type", out JsonElement discriminator)) + { + switch (discriminator.GetString()) + { + //case "azure_cosmos_db": return AzureCosmosDBChatExtensionConfiguration.DeserializeAzureCosmosDBChatExtensionConfiguration(element, options); + //case "azure_ml_index": return AzureMachineLearningIndexChatExtensionConfiguration.DeserializeAzureMachineLearningIndexChatExtensionConfiguration(element, options); + case "azure_search": return AzureSearchChatExtensionConfiguration.DeserializeAzureSearchChatExtensionConfiguration(element, options); + //case "elasticsearch": return ElasticsearchChatExtensionConfiguration.DeserializeElasticsearchChatExtensionConfiguration(element, options); + //case "pinecone": return PineconeChatExtensionConfiguration.DeserializePineconeChatExtensionConfiguration(element, options); + } + } + return UnknownAzureChatExtensionConfiguration.DeserializeUnknownAzureChatExtensionConfiguration(element, options); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(AzureChatExtensionConfiguration)} does not support writing '{options.Format}' format."); + } + } + + AzureChatExtensionConfiguration IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeAzureChatExtensionConfiguration(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(AzureChatExtensionConfiguration)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + ///// Deserializes the model from a raw response. + ///// The response to deserialize the model from. + //internal static AzureChatExtensionConfiguration FromResponse(Response response) + //{ + // using var document = JsonDocument.Parse(response.Content); + // return DeserializeAzureChatExtensionConfiguration(document.RootElement); + //} + + ///// Convert into a Utf8JsonRequestContent. + //internal virtual RequestContent ToRequestContent() + //{ + // var content = new Utf8JsonRequestContent(); + // content.JsonWriter.WriteObjectValue(this, new ModelReaderWriterOptions("W")); + // return content; + //} +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureChatExtensionConfiguration.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureChatExtensionConfiguration.cs new file mode 100644 index 000000000..807b35cd4 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureChatExtensionConfiguration.cs @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace AzureOpenAI.Models; + +/// +/// A representation of configuration data for a single Azure OpenAI chat extension. This will be used by a chat +/// completions request that should use Azure OpenAI chat extensions to augment the response behavior. +/// The use of this configuration is compatible only with Azure OpenAI. +/// Please note is the base class. According to the scenario, a derived class of the base class might need to be assigned here, or this property needs to be casted to one of the possible derived classes. +/// The available derived classes include , , , and . +/// +public abstract partial class AzureChatExtensionConfiguration +{ + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + + // TODO: Could this be IDictionary> or even + // IDictionary> in some cases. What would that do? + // + // Note: No, because you don't have the T. + private protected IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + protected AzureChatExtensionConfiguration() + { + } + + /// Initializes a new instance of . + /// + /// The label for the type of an Azure chat extension. This typically corresponds to a matching Azure resource. + /// Azure chat extensions are only compatible with Azure OpenAI. + /// + /// Keeps track of any properties unknown to the library. + internal AzureChatExtensionConfiguration(AzureChatExtensionType type, IDictionary serializedAdditionalRawData) + { + Type = type; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// + /// The label for the type of an Azure chat extension. This typically corresponds to a matching Azure resource. + /// Azure chat extensions are only compatible with Azure OpenAI. + /// + internal AzureChatExtensionType Type { get; set; } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureChatExtensionType.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureChatExtensionType.cs new file mode 100644 index 000000000..7f0b3bb95 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureChatExtensionType.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.ComponentModel; + +namespace AzureOpenAI.Models; + +/// +/// A representation of configuration data for a single Azure OpenAI chat extension. This will be used by a chat +/// completions request that should use Azure OpenAI chat extensions to augment the response behavior. +/// The use of this configuration is compatible only with Azure OpenAI. +/// +internal readonly partial struct AzureChatExtensionType : IEquatable +{ + private readonly string _value; + + /// Initializes a new instance of . + /// is null. + public AzureChatExtensionType(string value) + { + _value = value ?? throw new ArgumentNullException(nameof(value)); + } + + private const string AzureSearchValue = "azure_search"; + private const string AzureMachineLearningIndexValue = "azure_ml_index"; + private const string AzureCosmosDBValue = "azure_cosmos_db"; + private const string ElasticsearchValue = "elasticsearch"; + private const string PineconeValue = "pinecone"; + + /// Represents the use of Azure AI Search as an Azure OpenAI chat extension. + public static AzureChatExtensionType AzureSearch { get; } = new AzureChatExtensionType(AzureSearchValue); + /// Represents the use of Azure Machine Learning index as an Azure OpenAI chat extension. + public static AzureChatExtensionType AzureMachineLearningIndex { get; } = new AzureChatExtensionType(AzureMachineLearningIndexValue); + /// Represents the use of Azure Cosmos DB as an Azure OpenAI chat extension. + public static AzureChatExtensionType AzureCosmosDB { get; } = new AzureChatExtensionType(AzureCosmosDBValue); + /// Represents the use of Elasticsearch® index as an Azure OpenAI chat extension. + public static AzureChatExtensionType Elasticsearch { get; } = new AzureChatExtensionType(ElasticsearchValue); + /// Represents the use of Pinecone index as an Azure OpenAI chat extension. + public static AzureChatExtensionType Pinecone { get; } = new AzureChatExtensionType(PineconeValue); + /// Determines if two values are the same. + public static bool operator ==(AzureChatExtensionType left, AzureChatExtensionType right) => left.Equals(right); + /// Determines if two values are not the same. + public static bool operator !=(AzureChatExtensionType left, AzureChatExtensionType right) => !left.Equals(right); + /// Converts a string to a . + public static implicit operator AzureChatExtensionType(string value) => new AzureChatExtensionType(value); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => obj is AzureChatExtensionType other && Equals(other); + /// + public bool Equals(AzureChatExtensionType other) => string.Equals(_value, other._value, StringComparison.InvariantCultureIgnoreCase); + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => _value?.GetHashCode() ?? 0; + /// + public override string ToString() => _value; +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureCreateChatCompletionRequest.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureCreateChatCompletionRequest.cs new file mode 100644 index 000000000..928c8177d --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureCreateChatCompletionRequest.cs @@ -0,0 +1,70 @@ +using OpenAI.Models; +using System.ClientModel.Primitives; +using System.Diagnostics; +using System.Text.Json; + +namespace AzureOpenAI.Models; + +internal class AzureCreateChatCompletionRequest : IJsonModel +{ + private readonly CreateChatCompletionRequest _request; + private readonly JsonModelList? _dataSources; + + public AzureCreateChatCompletionRequest(CreateChatCompletionRequest request) + { + _request = request; + + if (request is not IJsonModel model) + { + throw new InvalidOperationException("TODO"); + } + + if (model.AdditionalProperties.TryGetValue("data_sources", out object? value)) + { + Debug.Assert(value is JsonModelList); + + _dataSources = (value as JsonModelList)!; + } + } + + AzureCreateChatCompletionRequest IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + throw new NotSupportedException("Not supported for input types."); + } + + AzureCreateChatCompletionRequest IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + throw new NotSupportedException("Not supported for input types."); + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) + => "J"; + + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + writer.WriteStartObject(); + + // Note that we write the base model differently in this context + ((IJsonModel)_request).Write(writer, new ModelReaderWriterOptions("W*")); + + // Write the additional Azure properties + if (_dataSources is not null) + { + writer.WritePropertyName("data_sources"); + ((IJsonModel)_dataSources).Write(writer, new ModelReaderWriterOptions("W")); + } + + writer.WriteEndObject(); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + return format switch + { + "J" => ModelReaderWriter.Write(this, options), + _ => throw new FormatException($"The model {nameof(CreateChatCompletionRequest)} does not support writing '{options.Format}' format."), + }; + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureSearchChatExtensionConfiguration.Serialization.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureSearchChatExtensionConfiguration.Serialization.cs new file mode 100644 index 000000000..43ea89117 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureSearchChatExtensionConfiguration.Serialization.cs @@ -0,0 +1,138 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace AzureOpenAI.Models; + +public partial class AzureSearchChatExtensionConfiguration : IJsonModel +{ + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(AzureSearchChatExtensionConfiguration)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + writer.WritePropertyName("parameters"u8); + writer.WriteObjectValue(Parameters, options); + writer.WritePropertyName("type"u8); + writer.WriteStringValue(Type.ToString()); + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + 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 + } + } + writer.WriteEndObject(); + } + + AzureSearchChatExtensionConfiguration IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(AzureSearchChatExtensionConfiguration)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeAzureSearchChatExtensionConfiguration(document.RootElement, options); + } + + internal static AzureSearchChatExtensionConfiguration DeserializeAzureSearchChatExtensionConfiguration(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= new ModelReaderWriterOptions("W"); + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + AzureSearchChatExtensionParameters parameters = default; + AzureChatExtensionType type = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("parameters"u8)) + { + parameters = AzureSearchChatExtensionParameters.DeserializeAzureSearchChatExtensionParameters(property.Value, options); + continue; + } + if (property.NameEquals("type"u8)) + { + type = new AzureChatExtensionType(property.Value.GetString()); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new AzureSearchChatExtensionConfiguration(type, serializedAdditionalRawData, parameters); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(AzureSearchChatExtensionConfiguration)} does not support writing '{options.Format}' format."); + } + } + + AzureSearchChatExtensionConfiguration IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeAzureSearchChatExtensionConfiguration(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(AzureSearchChatExtensionConfiguration)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + ///// Deserializes the model from a raw response. + ///// The response to deserialize the model from. + //internal static new AzureSearchChatExtensionConfiguration FromResponse(Response response) + //{ + // using var document = JsonDocument.Parse(response.Content); + // return DeserializeAzureSearchChatExtensionConfiguration(document.RootElement); + //} + + ///// Convert into a Utf8JsonRequestContent. + //internal override BinaryContent ToBinaryContent() + //{ + // var content = new Utf8JsonRequestContent(); + // content.JsonWriter.WriteObjectValue(this, new ModelReaderWriterOptions("W")); + // return content; + //} +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureSearchChatExtensionConfiguration.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureSearchChatExtensionConfiguration.cs new file mode 100644 index 000000000..d8a7e655f --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureSearchChatExtensionConfiguration.cs @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using OpenAI; +using System; +using System.Collections.Generic; + +namespace AzureOpenAI.Models; + +/// +/// A specific representation of configurable options for Azure Search when using it as an Azure OpenAI chat +/// extension. +/// +public partial class AzureSearchChatExtensionConfiguration : AzureChatExtensionConfiguration +{ + /// Initializes a new instance of . + /// The parameters to use when configuring Azure Search. + /// is null. + public AzureSearchChatExtensionConfiguration(AzureSearchChatExtensionParameters parameters) + { + Argument.AssertNotNull(parameters, nameof(parameters)); + + Type = AzureChatExtensionType.AzureSearch; + Parameters = parameters; + } + + /// Initializes a new instance of . + /// + /// The label for the type of an Azure chat extension. This typically corresponds to a matching Azure resource. + /// Azure chat extensions are only compatible with Azure OpenAI. + /// + /// Keeps track of any properties unknown to the library. + /// The parameters to use when configuring Azure Search. + internal AzureSearchChatExtensionConfiguration(AzureChatExtensionType type, IDictionary serializedAdditionalRawData, AzureSearchChatExtensionParameters parameters) : base(type, serializedAdditionalRawData) + { + Parameters = parameters; + } + + /// Initializes a new instance of for deserialization. + internal AzureSearchChatExtensionConfiguration() + { + } + + /// The parameters to use when configuring Azure Search. + public AzureSearchChatExtensionParameters Parameters { get; } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureSearchChatExtensionParameters.Serialization.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureSearchChatExtensionParameters.Serialization.cs new file mode 100644 index 000000000..c7c2a1a6a --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureSearchChatExtensionParameters.Serialization.cs @@ -0,0 +1,288 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace AzureOpenAI.Models; + +public partial class AzureSearchChatExtensionParameters : IJsonModel +{ + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(AzureSearchChatExtensionParameters)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + //if (Optional.IsDefined(Authentication)) + //{ + // writer.WritePropertyName("authentication"u8); + // writer.WriteObjectValue(Authentication, options); + //} + if (Optional.IsDefined(DocumentCount)) + { + writer.WritePropertyName("top_n_documents"u8); + writer.WriteNumberValue(DocumentCount.Value); + } + if (Optional.IsDefined(ShouldRestrictResultScope)) + { + writer.WritePropertyName("in_scope"u8); + writer.WriteBooleanValue(ShouldRestrictResultScope.Value); + } + if (Optional.IsDefined(Strictness)) + { + writer.WritePropertyName("strictness"u8); + writer.WriteNumberValue(Strictness.Value); + } + if (Optional.IsDefined(RoleInformation)) + { + writer.WritePropertyName("role_information"u8); + writer.WriteStringValue(RoleInformation); + } + writer.WritePropertyName("endpoint"u8); + writer.WriteStringValue(SearchEndpoint.AbsoluteUri); + writer.WritePropertyName("index_name"u8); + writer.WriteStringValue(IndexName); + //if (Optional.IsDefined(FieldMappingOptions)) + //{ + // writer.WritePropertyName("fields_mapping"u8); + // writer.WriteObjectValue(FieldMappingOptions, options); + //} + //if (Optional.IsDefined(QueryType)) + //{ + // writer.WritePropertyName("query_type"u8); + // writer.WriteStringValue(QueryType.Value.ToString()); + //} + if (Optional.IsDefined(SemanticConfiguration)) + { + writer.WritePropertyName("semantic_configuration"u8); + writer.WriteStringValue(SemanticConfiguration); + } + if (Optional.IsDefined(Filter)) + { + writer.WritePropertyName("filter"u8); + writer.WriteStringValue(Filter); + } + //if (Optional.IsDefined(EmbeddingDependency)) + //{ + // writer.WritePropertyName("embedding_dependency"u8); + // writer.WriteObjectValue(EmbeddingDependency, options); + //} + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + 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 + } + } + writer.WriteEndObject(); + } + + AzureSearchChatExtensionParameters IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(AzureSearchChatExtensionParameters)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeAzureSearchChatExtensionParameters(document.RootElement, options); + } + + internal static AzureSearchChatExtensionParameters DeserializeAzureSearchChatExtensionParameters(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= new ModelReaderWriterOptions("W"); + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + //OnYourDataAuthenticationOptions authentication = default; + int? topNDocuments = default; + bool? inScope = default; + int? strictness = default; + string roleInformation = default; + Uri endpoint = default; + string indexName = default; + //AzureSearchIndexFieldMappingOptions fieldsMapping = default; + //AzureSearchQueryType? queryType = default; + string semanticConfiguration = default; + string filter = default; + //OnYourDataVectorizationSource embeddingDependency = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + //if (property.NameEquals("authentication"u8)) + //{ + // if (property.Value.ValueKind == JsonValueKind.Null) + // { + // continue; + // } + // authentication = OnYourDataAuthenticationOptions.DeserializeOnYourDataAuthenticationOptions(property.Value, options); + // continue; + //} + if (property.NameEquals("top_n_documents"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + topNDocuments = property.Value.GetInt32(); + continue; + } + if (property.NameEquals("in_scope"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + inScope = property.Value.GetBoolean(); + continue; + } + if (property.NameEquals("strictness"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + strictness = property.Value.GetInt32(); + continue; + } + if (property.NameEquals("role_information"u8)) + { + roleInformation = property.Value.GetString(); + continue; + } + if (property.NameEquals("endpoint"u8)) + { + endpoint = new Uri(property.Value.GetString()); + continue; + } + if (property.NameEquals("index_name"u8)) + { + indexName = property.Value.GetString(); + continue; + } + //if (property.NameEquals("fields_mapping"u8)) + //{ + // if (property.Value.ValueKind == JsonValueKind.Null) + // { + // continue; + // } + // fieldsMapping = AzureSearchIndexFieldMappingOptions.DeserializeAzureSearchIndexFieldMappingOptions(property.Value, options); + // continue; + //} + //if (property.NameEquals("query_type"u8)) + //{ + // if (property.Value.ValueKind == JsonValueKind.Null) + // { + // continue; + // } + // queryType = new AzureSearchQueryType(property.Value.GetString()); + // continue; + //} + if (property.NameEquals("semantic_configuration"u8)) + { + semanticConfiguration = property.Value.GetString(); + continue; + } + if (property.NameEquals("filter"u8)) + { + filter = property.Value.GetString(); + continue; + } + //if (property.NameEquals("embedding_dependency"u8)) + //{ + // if (property.Value.ValueKind == JsonValueKind.Null) + // { + // continue; + // } + // embeddingDependency = OnYourDataVectorizationSource.DeserializeOnYourDataVectorizationSource(property.Value, options); + // continue; + //} + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new AzureSearchChatExtensionParameters( + //authentication, + topNDocuments, + inScope, + strictness, + roleInformation, + endpoint, + indexName, + //fieldsMapping, + //queryType, + semanticConfiguration, + filter, + //embeddingDependency, + serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(AzureSearchChatExtensionParameters)} does not support writing '{options.Format}' format."); + } + } + + AzureSearchChatExtensionParameters IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeAzureSearchChatExtensionParameters(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(AzureSearchChatExtensionParameters)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + ///// Deserializes the model from a raw response. + ///// The response to deserialize the model from. + //internal static AzureSearchChatExtensionParameters FromResponse(Response response) + //{ + // using var document = JsonDocument.Parse(response.Content); + // return DeserializeAzureSearchChatExtensionParameters(document.RootElement); + //} + + ///// Convert into a Utf8JsonRequestContent. + //internal virtual RequestContent ToRequestContent() + //{ + // var content = new Utf8JsonRequestContent(); + // content.JsonWriter.WriteObjectValue(this, new ModelReaderWriterOptions("W")); + // return content; + //} +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureSearchChatExtensionParameters.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureSearchChatExtensionParameters.cs new file mode 100644 index 000000000..a7548a0da --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/AzureSearchChatExtensionParameters.cs @@ -0,0 +1,146 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace AzureOpenAI.Models; + +/// Parameters for Azure Cognitive Search when used as an Azure OpenAI chat extension. The supported authentication types are APIKey, SystemAssignedManagedIdentity and UserAssignedManagedIdentity. +public partial class AzureSearchChatExtensionParameters +{ + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + /// The absolute endpoint path for the Azure Cognitive Search resource to use. + /// The name of the index to use as available in the referenced Azure Cognitive Search resource. + /// or is null. + public AzureSearchChatExtensionParameters(Uri searchEndpoint, string indexName) + { + Argument.AssertNotNull(searchEndpoint, nameof(searchEndpoint)); + Argument.AssertNotNull(indexName, nameof(indexName)); + + SearchEndpoint = searchEndpoint; + IndexName = indexName; + } + + /// Initializes a new instance of . + /// + /// The authentication method to use when accessing the defined data source. + /// Each data source type supports a specific set of available authentication methods; please see the documentation of + /// the data source for supported mechanisms. + /// If not otherwise provided, On Your Data will attempt to use System Managed Identity (default credential) + /// authentication. + /// Please note is the base class. According to the scenario, a derived class of the base class might need to be assigned here, or this property needs to be casted to one of the possible derived classes. + /// The available derived classes include , , , , , and . + /// + /// The configured top number of documents to feature for the configured query. + /// Whether queries should be restricted to use of indexed data. + /// The configured strictness of the search relevance filtering. The higher of strictness, the higher of the precision but lower recall of the answer. + /// Give the model instructions about how it should behave and any context it should reference when generating a response. You can describe the assistant's personality and tell it how to format responses. There's a 100 token limit for it, and it counts against the overall token limit. + /// The absolute endpoint path for the Azure Cognitive Search resource to use. + /// The name of the index to use as available in the referenced Azure Cognitive Search resource. + /// Customized field mapping behavior to use when interacting with the search index. + /// The query type to use with Azure Cognitive Search. + /// The additional semantic configuration for the query. + /// Search filter. + /// + /// The embedding dependency for vector search. + /// Please note is the base class. According to the scenario, a derived class of the base class might need to be assigned here, or this property needs to be casted to one of the possible derived classes. + /// The available derived classes include , and . + /// + /// Keeps track of any properties unknown to the library. + //internal AzureSearchChatExtensionParameters(OnYourDataAuthenticationOptions authentication, int? documentCount, bool? shouldRestrictResultScope, int? strictness, string roleInformation, Uri searchEndpoint, string indexName, AzureSearchIndexFieldMappingOptions fieldMappingOptions, AzureSearchQueryType? queryType, string semanticConfiguration, string filter, OnYourDataVectorizationSource embeddingDependency, IDictionary serializedAdditionalRawData) + internal AzureSearchChatExtensionParameters(int? documentCount, bool? shouldRestrictResultScope, int? strictness, string roleInformation, Uri searchEndpoint, string indexName, string semanticConfiguration, string filter, IDictionary serializedAdditionalRawData) + { + //Authentication = authentication; + DocumentCount = documentCount; + ShouldRestrictResultScope = shouldRestrictResultScope; + Strictness = strictness; + RoleInformation = roleInformation; + SearchEndpoint = searchEndpoint; + IndexName = indexName; + //FieldMappingOptions = fieldMappingOptions; + //QueryType = queryType; + SemanticConfiguration = semanticConfiguration; + Filter = filter; + //EmbeddingDependency = embeddingDependency; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// Initializes a new instance of for deserialization. + internal AzureSearchChatExtensionParameters() + { + } + + /// + /// The authentication method to use when accessing the defined data source. + /// Each data source type supports a specific set of available authentication methods; please see the documentation of + /// the data source for supported mechanisms. + /// If not otherwise provided, On Your Data will attempt to use System Managed Identity (default credential) + /// authentication. + /// Please note is the base class. According to the scenario, a derived class of the base class might need to be assigned here, or this property needs to be casted to one of the possible derived classes. + /// The available derived classes include , , , , , and . + /// + //public OnYourDataAuthenticationOptions Authentication { get; set; } + /// The configured top number of documents to feature for the configured query. + public int? DocumentCount { get; set; } + /// Whether queries should be restricted to use of indexed data. + public bool? ShouldRestrictResultScope { get; set; } + /// The configured strictness of the search relevance filtering. The higher of strictness, the higher of the precision but lower recall of the answer. + public int? Strictness { get; set; } + /// Give the model instructions about how it should behave and any context it should reference when generating a response. You can describe the assistant's personality and tell it how to format responses. There's a 100 token limit for it, and it counts against the overall token limit. + public string RoleInformation { get; set; } + /// The absolute endpoint path for the Azure Cognitive Search resource to use. + public Uri SearchEndpoint { get; } + /// The name of the index to use as available in the referenced Azure Cognitive Search resource. + public string IndexName { get; } + /// Customized field mapping behavior to use when interacting with the search index. + //public AzureSearchIndexFieldMappingOptions FieldMappingOptions { get; set; } + ///// The query type to use with Azure Cognitive Search. + //public AzureSearchQueryType? QueryType { get; set; } + /// The additional semantic configuration for the query. + public string SemanticConfiguration { get; set; } + /// Search filter. + public string Filter { get; set; } + ///// + ///// The embedding dependency for vector search. + ///// Please note is the base class. According to the scenario, a derived class of the base class might need to be assigned here, or this property needs to be casted to one of the possible derived classes. + ///// The available derived classes include , and . + ///// + //public OnYourDataVectorizationSource EmbeddingDependency { get; set; } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/CreateChatCompletionRequestExtensions.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/CreateChatCompletionRequestExtensions.cs new file mode 100644 index 000000000..d56e2a5a3 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/CreateChatCompletionRequestExtensions.cs @@ -0,0 +1,39 @@ +using OpenAI.Models; +using System.ClientModel; +using System.ClientModel.Primitives; +using System.Diagnostics; + +namespace AzureOpenAI.Models; + +public static class CreateChatCompletionRequestExtensions +{ + public static IList GetDataSources(this CreateChatCompletionRequest request) + { + if (request is not IJsonModel model) + { + throw new InvalidOperationException("TODO"); + } + + JsonModelList dataSources; + + if (model.AdditionalProperties.TryGetValue("data_sources", out object? value)) + { + Debug.Assert(value is JsonModelList); + + dataSources = (value as JsonModelList)!; + } + else + { + dataSources = []; + model.AdditionalProperties.Add("data_sources", dataSources); + } + + return dataSources; + } + + public static BinaryContent ToBinaryContent(this CreateChatCompletionRequest request) + { + AzureCreateChatCompletionRequest azureRequest = new(request); + return BinaryContent.Create(azureRequest, new ModelReaderWriterOptions("W")); + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/UnknownAzureChatExtensionConfiguration.Serialization.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/UnknownAzureChatExtensionConfiguration.Serialization.cs new file mode 100644 index 000000000..b2f7802be --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/UnknownAzureChatExtensionConfiguration.Serialization.cs @@ -0,0 +1,129 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace AzureOpenAI.Models; + +internal partial class UnknownAzureChatExtensionConfiguration : IJsonModel +{ + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(AzureChatExtensionConfiguration)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + writer.WritePropertyName("type"u8); + writer.WriteStringValue(Type.ToString()); + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + 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 + } + } + writer.WriteEndObject(); + } + + AzureChatExtensionConfiguration IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(AzureChatExtensionConfiguration)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeAzureChatExtensionConfiguration(document.RootElement, options); + } + + internal static UnknownAzureChatExtensionConfiguration DeserializeUnknownAzureChatExtensionConfiguration(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= new ModelReaderWriterOptions("W"); + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + AzureChatExtensionType type = "Unknown"; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("type"u8)) + { + type = new AzureChatExtensionType(property.Value.GetString()); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new UnknownAzureChatExtensionConfiguration(type, serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(AzureChatExtensionConfiguration)} does not support writing '{options.Format}' format."); + } + } + + AzureChatExtensionConfiguration IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeAzureChatExtensionConfiguration(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(AzureChatExtensionConfiguration)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + ///// Deserializes the model from a raw response. + ///// The response to deserialize the model from. + //internal static new UnknownAzureChatExtensionConfiguration FromResponse(Response response) + //{ + // using var document = JsonDocument.Parse(response.Content); + // return DeserializeUnknownAzureChatExtensionConfiguration(document.RootElement); + //} + + ///// Convert into a Utf8JsonRequestContent. + //internal override RequestContent ToRequestContent() + //{ + // var content = new Utf8JsonRequestContent(); + // content.JsonWriter.WriteObjectValue(this, new ModelReaderWriterOptions("W")); + // return content; + //} +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/UnknownAzureChatExtensionConfiguration.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/UnknownAzureChatExtensionConfiguration.cs new file mode 100644 index 000000000..5d9b43d3b --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Input/UnknownAzureChatExtensionConfiguration.cs @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace AzureOpenAI.Models; + +/// Unknown version of AzureChatExtensionConfiguration. +internal partial class UnknownAzureChatExtensionConfiguration : AzureChatExtensionConfiguration +{ + /// Initializes a new instance of . + /// + /// The label for the type of an Azure chat extension. This typically corresponds to a matching Azure resource. + /// Azure chat extensions are only compatible with Azure OpenAI. + /// + /// Keeps track of any properties unknown to the library. + internal UnknownAzureChatExtensionConfiguration(AzureChatExtensionType type, IDictionary serializedAdditionalRawData) : base(type, serializedAdditionalRawData) + { + } + + /// Initializes a new instance of for deserialization. + internal UnknownAzureChatExtensionConfiguration() + { + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/AzureChatExtensionDataSourceResponseCitation.Serialization.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/AzureChatExtensionDataSourceResponseCitation.Serialization.cs new file mode 100644 index 000000000..11773544c --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/AzureChatExtensionDataSourceResponseCitation.Serialization.cs @@ -0,0 +1,179 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace AzureOpenAI.Models; + +public partial class AzureChatExtensionDataSourceResponseCitation : IJsonModel +{ + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(AzureChatExtensionDataSourceResponseCitation)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + writer.WritePropertyName("content"u8); + writer.WriteStringValue(Content); + if (Optional.IsDefined(Title)) + { + writer.WritePropertyName("title"u8); + writer.WriteStringValue(Title); + } + if (Optional.IsDefined(Url)) + { + writer.WritePropertyName("url"u8); + writer.WriteStringValue(Url); + } + if (Optional.IsDefined(Filepath)) + { + writer.WritePropertyName("filepath"u8); + writer.WriteStringValue(Filepath); + } + if (Optional.IsDefined(ChunkId)) + { + writer.WritePropertyName("chunk_id"u8); + writer.WriteStringValue(ChunkId); + } + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + 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 + } + } + writer.WriteEndObject(); + } + + AzureChatExtensionDataSourceResponseCitation IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(AzureChatExtensionDataSourceResponseCitation)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeAzureChatExtensionDataSourceResponseCitation(document.RootElement, options); + } + + internal static AzureChatExtensionDataSourceResponseCitation DeserializeAzureChatExtensionDataSourceResponseCitation(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= new ModelReaderWriterOptions("W"); + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + string content = default; + string title = default; + string url = default; + string filepath = default; + string chunkId = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("content"u8)) + { + content = property.Value.GetString(); + continue; + } + if (property.NameEquals("title"u8)) + { + title = property.Value.GetString(); + continue; + } + if (property.NameEquals("url"u8)) + { + url = property.Value.GetString(); + continue; + } + if (property.NameEquals("filepath"u8)) + { + filepath = property.Value.GetString(); + continue; + } + if (property.NameEquals("chunk_id"u8)) + { + chunkId = property.Value.GetString(); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new AzureChatExtensionDataSourceResponseCitation( + content, + title, + url, + filepath, + chunkId, + serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(AzureChatExtensionDataSourceResponseCitation)} does not support writing '{options.Format}' format."); + } + } + + AzureChatExtensionDataSourceResponseCitation IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeAzureChatExtensionDataSourceResponseCitation(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(AzureChatExtensionDataSourceResponseCitation)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + ///// Deserializes the model from a raw response. + ///// The response to deserialize the model from. + //internal static AzureChatExtensionDataSourceResponseCitation FromResponse(Response response) + //{ + // using var document = JsonDocument.Parse(response.Content); + // return DeserializeAzureChatExtensionDataSourceResponseCitation(document.RootElement); + //} + + ///// Convert into a Utf8JsonRequestContent. + //internal virtual RequestContent ToRequestContent() + //{ + // var content = new Utf8JsonRequestContent(); + // content.JsonWriter.WriteObjectValue(this, new ModelReaderWriterOptions("W")); + // return content; + //} +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/AzureChatExtensionDataSourceResponseCitation.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/AzureChatExtensionDataSourceResponseCitation.cs new file mode 100644 index 000000000..4c4e65481 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/AzureChatExtensionDataSourceResponseCitation.cs @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace AzureOpenAI.Models; + +/// +/// A single instance of additional context information available when Azure OpenAI chat extensions are involved +/// in the generation of a corresponding chat completions response. This context information is only populated when +/// using an Azure OpenAI request configured to use a matching extension. +/// +public partial class AzureChatExtensionDataSourceResponseCitation +{ + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + /// The content of the citation. + /// is null. + internal AzureChatExtensionDataSourceResponseCitation(string content) + { + Argument.AssertNotNull(content, nameof(content)); + + Content = content; + } + + /// Initializes a new instance of . + /// The content of the citation. + /// The title of the citation. + /// The URL of the citation. + /// The file path of the citation. + /// The chunk ID of the citation. + /// Keeps track of any properties unknown to the library. + internal AzureChatExtensionDataSourceResponseCitation(string content, string title, string url, string filepath, string chunkId, IDictionary serializedAdditionalRawData) + { + Content = content; + Title = title; + Url = url; + Filepath = filepath; + ChunkId = chunkId; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// Initializes a new instance of for deserialization. + internal AzureChatExtensionDataSourceResponseCitation() + { + } + + /// The content of the citation. + public string Content { get; } + /// The title of the citation. + public string Title { get; } + /// The URL of the citation. + public string Url { get; } + /// The file path of the citation. + public string Filepath { get; } + /// The chunk ID of the citation. + public string ChunkId { get; } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/AzureChatExtensionsMessageContext.Serialization.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/AzureChatExtensionsMessageContext.Serialization.cs new file mode 100644 index 000000000..b5367eb5f --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/AzureChatExtensionsMessageContext.Serialization.cs @@ -0,0 +1,157 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.ClientModel.Primitives; +using System.Text.Json; + +namespace AzureOpenAI.Models; + +public partial class AzureChatExtensionsMessageContext : IJsonModel +{ + void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(AzureChatExtensionsMessageContext)} does not support writing '{format}' format."); + } + + writer.WriteStartObject(); + if (Optional.IsCollectionDefined(Citations)) + { + writer.WritePropertyName("citations"u8); + writer.WriteStartArray(); + foreach (var item in Citations) + { + writer.WriteObjectValue(item, options); + } + writer.WriteEndArray(); + } + if (Optional.IsDefined(Intent)) + { + writer.WritePropertyName("intent"u8); + writer.WriteStringValue(Intent); + } + if (options.Format != "W" && _serializedAdditionalRawData != null) + { + foreach (var item in _serializedAdditionalRawData) + { + 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 + } + } + writer.WriteEndObject(); + } + + AzureChatExtensionsMessageContext IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J") + { + throw new FormatException($"The model {nameof(AzureChatExtensionsMessageContext)} does not support reading '{format}' format."); + } + + using JsonDocument document = JsonDocument.ParseValue(ref reader); + return DeserializeAzureChatExtensionsMessageContext(document.RootElement, options); + } + + internal static AzureChatExtensionsMessageContext DeserializeAzureChatExtensionsMessageContext(JsonElement element, ModelReaderWriterOptions options = null) + { + options ??= new ModelReaderWriterOptions("W"); + + if (element.ValueKind == JsonValueKind.Null) + { + return null; + } + IReadOnlyList citations = default; + string intent = default; + IDictionary serializedAdditionalRawData = default; + Dictionary rawDataDictionary = new Dictionary(); + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("citations"u8)) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + List array = new List(); + foreach (var item in property.Value.EnumerateArray()) + { + array.Add(AzureChatExtensionDataSourceResponseCitation.DeserializeAzureChatExtensionDataSourceResponseCitation(item, options)); + } + citations = array; + continue; + } + if (property.NameEquals("intent"u8)) + { + intent = property.Value.GetString(); + continue; + } + if (options.Format != "W") + { + rawDataDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + } + } + serializedAdditionalRawData = rawDataDictionary; + return new AzureChatExtensionsMessageContext(citations ?? new ChangeTrackingList(), intent, serializedAdditionalRawData); + } + + BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + return ModelReaderWriter.Write(this, options); + default: + throw new FormatException($"The model {nameof(AzureChatExtensionsMessageContext)} does not support writing '{options.Format}' format."); + } + } + + AzureChatExtensionsMessageContext IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + { + var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + + switch (format) + { + case "J": + { + using JsonDocument document = JsonDocument.Parse(data); + return DeserializeAzureChatExtensionsMessageContext(document.RootElement, options); + } + default: + throw new FormatException($"The model {nameof(AzureChatExtensionsMessageContext)} does not support reading '{options.Format}' format."); + } + } + + string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; + + ///// Deserializes the model from a raw response. + ///// The response to deserialize the model from. + //internal static AzureChatExtensionsMessageContext FromResponse(Response response) + //{ + // using var document = JsonDocument.Parse(response.Content); + // return DeserializeAzureChatExtensionsMessageContext(document.RootElement); + //} + + ///// Convert into a Utf8JsonRequestContent. + //internal virtual RequestContent ToRequestContent() + //{ + // var content = new Utf8JsonRequestContent(); + // content.JsonWriter.WriteObjectValue(this, new ModelReaderWriterOptions("W")); + // return content; + //} +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/AzureChatExtensionsMessageContext.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/AzureChatExtensionsMessageContext.cs new file mode 100644 index 000000000..ac4e3c880 --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/AzureChatExtensionsMessageContext.cs @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace AzureOpenAI.Models; + +/// +/// A representation of the additional context information available when Azure OpenAI chat extensions are involved +/// in the generation of a corresponding chat completions response. This context information is only populated when +/// using an Azure OpenAI request configured to use a matching extension. +/// +public partial class AzureChatExtensionsMessageContext +{ + /// + /// Keeps track of any properties unknown to the library. + /// + /// To assign an object to the value of this property use . + /// + /// + /// To assign an already formatted json string to this property use . + /// + /// + /// Examples: + /// + /// + /// BinaryData.FromObjectAsJson("foo") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromString("\"foo\"") + /// Creates a payload of "foo". + /// + /// + /// BinaryData.FromObjectAsJson(new { key = "value" }) + /// Creates a payload of { "key": "value" }. + /// + /// + /// BinaryData.FromString("{\"key\": \"value\"}") + /// Creates a payload of { "key": "value" }. + /// + /// + /// + /// + private IDictionary _serializedAdditionalRawData; + + /// Initializes a new instance of . + internal AzureChatExtensionsMessageContext() + { + Citations = new ChangeTrackingList(); + } + + /// Initializes a new instance of . + /// + /// The contextual information associated with the Azure chat extensions used for a chat completions request. + /// These messages describe the data source retrievals, plugin invocations, and other intermediate steps taken in the + /// course of generating a chat completions response that was augmented by capabilities from Azure OpenAI chat + /// extensions. + /// + /// The detected intent from the chat history, used to pass to the next turn to carry over the context. + /// Keeps track of any properties unknown to the library. + internal AzureChatExtensionsMessageContext(IReadOnlyList citations, string intent, IDictionary serializedAdditionalRawData) + { + Citations = citations; + Intent = intent; + _serializedAdditionalRawData = serializedAdditionalRawData; + } + + /// + /// The contextual information associated with the Azure chat extensions used for a chat completions request. + /// These messages describe the data source retrievals, plugin invocations, and other intermediate steps taken in the + /// course of generating a chat completions response that was augmented by capabilities from Azure OpenAI chat + /// extensions. + /// + public IReadOnlyList Citations { get; } + /// The detected intent from the chat history, used to pass to the next turn to carry over the context. + public string Intent { get; } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/ChatCompletionResponseMessageExtensions.cs b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/ChatCompletionResponseMessageExtensions.cs new file mode 100644 index 000000000..2c62b0eaa --- /dev/null +++ b/tsp-output/@azure-tools/typespec-csharp/azoai/AzureOpenAI/Models/Output/ChatCompletionResponseMessageExtensions.cs @@ -0,0 +1,39 @@ +using OpenAI.Models; +using System.ClientModel.Primitives; + +namespace AzureOpenAI.Models; + +public static class ChatCompletionResponseMessageExtensions +{ + // Output property + public static AzureChatExtensionsMessageContext? GetAzureExtensionsContext(this ChatCompletionResponseMessage message) + { + if (message is not IJsonModel model) + { + throw new InvalidOperationException("TODO"); + } + + if (!model.AdditionalProperties.TryGetValue("context", out object? value)) + { + return null; + } + + // It's either deserialized already or not. Find out now. + // This should work for all cases because we know the contract regarding + // BinaryData values. + if (value is BinaryData serializedValue) + { + // Qn: when can Read return null? + var deserializedValue = ModelReaderWriter.Read(serializedValue)!; + model.AdditionalProperties["context"] = deserializedValue; + return deserializedValue; + } + + if (value is not AzureChatExtensionsMessageContext context) + { + throw new InvalidOperationException($"'context' value is unexpected type: '{value.GetType()}'."); + } + + return context; + } +} diff --git a/tsp-output/@azure-tools/typespec-csharp/src/Generated/Chat.cs b/tsp-output/@azure-tools/typespec-csharp/src/Generated/Chat.cs index b42111af1..f142108fc 100644 --- a/tsp-output/@azure-tools/typespec-csharp/src/Generated/Chat.cs +++ b/tsp-output/@azure-tools/typespec-csharp/src/Generated/Chat.cs @@ -33,7 +33,7 @@ protected Chat() /// The HTTP pipeline for sending and receiving REST requests and responses. /// The key credential to copy. /// OpenAI Endpoint. - internal Chat(ClientPipeline pipeline, ApiKeyCredential keyCredential, Uri endpoint) + protected internal Chat(ClientPipeline pipeline, ApiKeyCredential keyCredential, Uri endpoint) { _pipeline = pipeline; _keyCredential = keyCredential; diff --git a/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/ChatCompletionResponseMessage.Serialization.cs b/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/ChatCompletionResponseMessage.Serialization.cs index 6096b65c4..308ae7367 100644 --- a/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/ChatCompletionResponseMessage.Serialization.cs +++ b/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/ChatCompletionResponseMessage.Serialization.cs @@ -10,9 +10,9 @@ namespace OpenAI.Models { - public partial class ChatCompletionResponseMessage : IJsonModel + public partial class ChatCompletionResponseMessage : JsonModel { - void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + protected override void WriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) { var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; if (format != "J") @@ -47,25 +47,14 @@ void IJsonModel.Write(Utf8JsonWriter writer, Mode writer.WritePropertyName("function_call"u8); writer.WriteObjectValue(FunctionCall, options); } - if (options.Format != "W" && _serializedAdditionalRawData != null) + if (options.Format != "W") { - foreach (var item in _serializedAdditionalRawData) - { - 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 - } + WriteUnknownProperties(writer, options); } writer.WriteEndObject(); } - ChatCompletionResponseMessage IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + protected override ChatCompletionResponseMessage CreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) { var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; if (format != "J") @@ -73,34 +62,25 @@ ChatCompletionResponseMessage IJsonModel.Create(r throw new FormatException($"The model {nameof(ChatCompletionResponseMessage)} does not support reading '{format}' format."); } + // TODO: use Reader APIs using JsonDocument document = JsonDocument.ParseValue(ref reader); - return DeserializeChatCompletionResponseMessage(document.RootElement, options); - } - - internal static ChatCompletionResponseMessage DeserializeChatCompletionResponseMessage(JsonElement element, ModelReaderWriterOptions options = null) - { + JsonElement element = document.RootElement; options ??= new ModelReaderWriterOptions("W"); if (element.ValueKind == JsonValueKind.Null) { return null; } - string content = default; - IReadOnlyList toolCalls = default; - ChatCompletionResponseMessageRole role = default; - ChatCompletionResponseMessageFunctionCall functionCall = default; - IDictionary serializedAdditionalRawData = default; - Dictionary additionalPropertiesDictionary = new Dictionary(); foreach (var property in element.EnumerateObject()) { if (property.NameEquals("content"u8)) { if (property.Value.ValueKind == JsonValueKind.Null) { - content = null; + Content = null; continue; } - content = property.Value.GetString(); + Content = property.Value.GetString(); continue; } if (property.NameEquals("tool_calls"u8)) @@ -114,12 +94,12 @@ internal static ChatCompletionResponseMessage DeserializeChatCompletionResponseM { array.Add(ChatCompletionMessageToolCall.DeserializeChatCompletionMessageToolCall(item, options)); } - toolCalls = array; + ToolCalls = array; continue; } if (property.NameEquals("role"u8)) { - role = new ChatCompletionResponseMessageRole(property.Value.GetString()); + Role = new ChatCompletionResponseMessageRole(property.Value.GetString()); continue; } if (property.NameEquals("function_call"u8)) @@ -128,55 +108,23 @@ internal static ChatCompletionResponseMessage DeserializeChatCompletionResponseM { continue; } - functionCall = ChatCompletionResponseMessageFunctionCall.DeserializeChatCompletionResponseMessageFunctionCall(property.Value, options); + FunctionCall = ChatCompletionResponseMessageFunctionCall.DeserializeChatCompletionResponseMessageFunctionCall(property.Value, options); continue; } if (options.Format != "W") { - additionalPropertiesDictionary.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); + // TODO: use Reader APIs + ((IJsonModel)this).AdditionalProperties.Add(property.Name, BinaryData.FromString(property.Value.GetRawText())); } } - serializedAdditionalRawData = additionalPropertiesDictionary; - return new ChatCompletionResponseMessage(content, toolCalls ?? new ChangeTrackingList(), role, functionCall, serializedAdditionalRawData); - } - - BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) - { - var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; - - switch (format) - { - case "J": - return ModelReaderWriter.Write(this, options); - default: - throw new FormatException($"The model {nameof(ChatCompletionResponseMessage)} does not support writing '{options.Format}' format."); - } - } - - ChatCompletionResponseMessage IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) - { - var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; - - switch (format) - { - case "J": - { - using JsonDocument document = JsonDocument.Parse(data); - return DeserializeChatCompletionResponseMessage(document.RootElement, options); - } - default: - throw new FormatException($"The model {nameof(ChatCompletionResponseMessage)} does not support reading '{options.Format}' format."); - } + return this; } - string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; - /// Deserializes the model from a raw response. /// The result to deserialize the model from. internal static ChatCompletionResponseMessage FromResponse(PipelineResponse response) { - using var document = JsonDocument.Parse(response.Content); - return DeserializeChatCompletionResponseMessage(document.RootElement); + return ModelReaderWriter.Read(response.Content); } /// Convert into a Utf8JsonRequestBody. diff --git a/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/ChatCompletionResponseMessage.cs b/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/ChatCompletionResponseMessage.cs index d4e71edb8..b6bb2cb11 100644 --- a/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/ChatCompletionResponseMessage.cs +++ b/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/ChatCompletionResponseMessage.cs @@ -10,59 +10,18 @@ namespace OpenAI.Models /// The ChatCompletionResponseMessage. public partial class ChatCompletionResponseMessage { - /// - /// Keeps track of any properties unknown to the library. - /// - /// To assign an object to the value of this property use . - /// - /// - /// To assign an already formatted json string to this property use . - /// - /// - /// Examples: - /// - /// - /// BinaryData.FromObjectAsJson("foo") - /// Creates a payload of "foo". - /// - /// - /// BinaryData.FromString("\"foo\"") - /// Creates a payload of "foo". - /// - /// - /// BinaryData.FromObjectAsJson(new { key = "value" }) - /// Creates a payload of { "key": "value" }. - /// - /// - /// BinaryData.FromString("{\"key\": \"value\"}") - /// Creates a payload of { "key": "value" }. - /// - /// - /// - /// - private IDictionary _serializedAdditionalRawData; - - /// Initializes a new instance of . - /// The contents of the message. - internal ChatCompletionResponseMessage(string content) - { - Content = content; - ToolCalls = new ChangeTrackingList(); - } - /// Initializes a new instance of . /// The contents of the message. /// /// The role of the author of this message. /// Deprecated and replaced by `tool_calls`. The name and arguments of a function that should be called, as generated by the model. /// Keeps track of any properties unknown to the library. - internal ChatCompletionResponseMessage(string content, IReadOnlyList toolCalls, ChatCompletionResponseMessageRole role, ChatCompletionResponseMessageFunctionCall functionCall, IDictionary serializedAdditionalRawData) + internal ChatCompletionResponseMessage(string content, IReadOnlyList toolCalls, ChatCompletionResponseMessageRole role, ChatCompletionResponseMessageFunctionCall functionCall, IDictionary serializedAdditionalRawData) { Content = content; ToolCalls = toolCalls; Role = role; FunctionCall = functionCall; - _serializedAdditionalRawData = serializedAdditionalRawData; } /// Initializes a new instance of for deserialization. @@ -71,13 +30,13 @@ internal ChatCompletionResponseMessage() } /// The contents of the message. - public string Content { get; } + public string Content { get; private set; } /// Gets the tool calls. - public IReadOnlyList ToolCalls { get; } + public IReadOnlyList ToolCalls { get; private set; } /// The role of the author of this message. - public ChatCompletionResponseMessageRole Role { get; } = ChatCompletionResponseMessageRole.Assistant; + public ChatCompletionResponseMessageRole Role { get; private set; } = ChatCompletionResponseMessageRole.Assistant; /// Deprecated and replaced by `tool_calls`. The name and arguments of a function that should be called, as generated by the model. - public ChatCompletionResponseMessageFunctionCall FunctionCall { get; } + public ChatCompletionResponseMessageFunctionCall FunctionCall { get; private set; } } } diff --git a/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/CreateChatCompletionRequest.Serialization.cs b/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/CreateChatCompletionRequest.Serialization.cs index 9f3ea44b8..0d8348203 100644 --- a/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/CreateChatCompletionRequest.Serialization.cs +++ b/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/CreateChatCompletionRequest.Serialization.cs @@ -10,17 +10,24 @@ namespace OpenAI.Models { - public partial class CreateChatCompletionRequest : IJsonModel + public partial class CreateChatCompletionRequest : JsonModel { - void IJsonModel.Write(Utf8JsonWriter writer, ModelReaderWriterOptions options) + protected override void WriteCore(Utf8JsonWriter writer, ModelReaderWriterOptions options) { - var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; - if (format != "J") + // Note: support format "W*" that doesn't write start/end object + // to enable extending write routine. + var format = (options.Format == "W" || options.Format == "W*") ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; + if (format != "J" && format != "J*") { throw new FormatException($"The model {nameof(CreateChatCompletionRequest)} does not support writing '{format}' format."); } - writer.WriteStartObject(); + if (format == "J") + { + // don't write for "W*" + writer.WriteStartObject(); + } + writer.WritePropertyName("messages"u8); writer.WriteStartArray(); foreach (var item in Messages) @@ -31,7 +38,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelR continue; } #if NET6_0_OR_GREATER - writer.WriteRawValue(item); + writer.WriteRawValue(item); #else using (JsonDocument document = JsonDocument.Parse(item)) { @@ -155,7 +162,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelR { writer.WritePropertyName("stop"u8); #if NET6_0_OR_GREATER - writer.WriteRawValue(Stop); + writer.WriteRawValue(Stop); #else using (JsonDocument document = JsonDocument.Parse(Stop)) { @@ -218,7 +225,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelR { writer.WritePropertyName("tool_choice"u8); #if NET6_0_OR_GREATER - writer.WriteRawValue(ToolChoice); + writer.WriteRawValue(ToolChoice); #else using (JsonDocument document = JsonDocument.Parse(ToolChoice)) { @@ -235,7 +242,7 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelR { writer.WritePropertyName("function_call"u8); #if NET6_0_OR_GREATER - writer.WriteRawValue(FunctionCall); + writer.WriteRawValue(FunctionCall); #else using (JsonDocument document = JsonDocument.Parse(FunctionCall)) { @@ -253,25 +260,18 @@ void IJsonModel.Write(Utf8JsonWriter writer, ModelR } writer.WriteEndArray(); } - if (options.Format != "W" && _serializedAdditionalRawData != null) + if (options.Format != "W") { - foreach (var item in _serializedAdditionalRawData) - { - 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 - } + WriteUnknownProperties(writer, options); + } + if (format == "J") + { + // don't write for "W*" + writer.WriteEndObject(); } - writer.WriteEndObject(); } - CreateChatCompletionRequest IJsonModel.Create(ref Utf8JsonReader reader, ModelReaderWriterOptions options) + protected override CreateChatCompletionRequest CreateCore(ref Utf8JsonReader reader, ModelReaderWriterOptions options) { var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; if (format != "J") @@ -311,8 +311,8 @@ internal static CreateChatCompletionRequest DeserializeCreateChatCompletionReque string user = default; BinaryData functionCall = default; IList functions = default; - IDictionary serializedAdditionalRawData = default; - Dictionary additionalPropertiesDictionary = new Dictionary(); + IDictionary serializedAdditionalRawData = default; + Dictionary additionalPropertiesDictionary = new Dictionary(); foreach (var property in element.EnumerateObject()) { if (property.NameEquals("messages"u8)) @@ -551,37 +551,15 @@ internal static CreateChatCompletionRequest DeserializeCreateChatCompletionReque serializedAdditionalRawData); } - BinaryData IPersistableModel.Write(ModelReaderWriterOptions options) - { - var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; - - switch (format) - { - case "J": - return ModelReaderWriter.Write(this, options); - default: - throw new FormatException($"The model {nameof(CreateChatCompletionRequest)} does not support writing '{options.Format}' format."); - } - } - - CreateChatCompletionRequest IPersistableModel.Create(BinaryData data, ModelReaderWriterOptions options) + protected override string GetFormatFromOptionsCore(ModelReaderWriterOptions options) { - var format = options.Format == "W" ? ((IPersistableModel)this).GetFormatFromOptions(options) : options.Format; - - switch (format) + return options.Format switch { - case "J": - { - using JsonDocument document = JsonDocument.Parse(data); - return DeserializeCreateChatCompletionRequest(document.RootElement, options); - } - default: - throw new FormatException($"The model {nameof(CreateChatCompletionRequest)} does not support reading '{options.Format}' format."); - } + "W*" => "J*", + _ => "J" + }; } - string IPersistableModel.GetFormatFromOptions(ModelReaderWriterOptions options) => "J"; - /// Deserializes the model from a raw response. /// The result to deserialize the model from. internal static CreateChatCompletionRequest FromResponse(PipelineResponse response) diff --git a/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/CreateChatCompletionRequest.cs b/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/CreateChatCompletionRequest.cs index 29676d50a..4f23bf189 100644 --- a/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/CreateChatCompletionRequest.cs +++ b/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/CreateChatCompletionRequest.cs @@ -11,38 +11,6 @@ namespace OpenAI.Models /// The CreateChatCompletionRequest. public partial class CreateChatCompletionRequest { - /// - /// Keeps track of any properties unknown to the library. - /// - /// To assign an object to the value of this property use . - /// - /// - /// To assign an already formatted json string to this property use . - /// - /// - /// Examples: - /// - /// - /// BinaryData.FromObjectAsJson("foo") - /// Creates a payload of "foo". - /// - /// - /// BinaryData.FromString("\"foo\"") - /// Creates a payload of "foo". - /// - /// - /// BinaryData.FromObjectAsJson(new { key = "value" }) - /// Creates a payload of { "key": "value" }. - /// - /// - /// BinaryData.FromString("{\"key\": \"value\"}") - /// Creates a payload of { "key": "value" }. - /// - /// - /// - /// - private IDictionary _serializedAdditionalRawData; - /// Initializes a new instance of . /// /// A list of messages comprising the conversation so far. @@ -187,7 +155,7 @@ public CreateChatCompletionRequest(IEnumerable messages, CreateChatC /// A list of functions the model may generate JSON inputs for. /// /// Keeps track of any properties unknown to the library. - internal CreateChatCompletionRequest(IList messages, CreateChatCompletionRequestModel model, double? frequencyPenalty, IDictionary logitBias, bool? logprobs, long? topLogprobs, long? maxTokens, long? n, double? presencePenalty, CreateChatCompletionRequestResponseFormat responseFormat, long? seed, BinaryData stop, bool? stream, double? temperature, double? topP, IList tools, BinaryData toolChoice, string user, BinaryData functionCall, IList functions, IDictionary serializedAdditionalRawData) + internal CreateChatCompletionRequest(IList messages, CreateChatCompletionRequestModel model, double? frequencyPenalty, IDictionary logitBias, bool? logprobs, long? topLogprobs, long? maxTokens, long? n, double? presencePenalty, CreateChatCompletionRequestResponseFormat responseFormat, long? seed, BinaryData stop, bool? stream, double? temperature, double? topP, IList tools, BinaryData toolChoice, string user, BinaryData functionCall, IList functions, IDictionary serializedAdditionalRawData) { Messages = messages; Model = model; @@ -209,7 +177,6 @@ internal CreateChatCompletionRequest(IList messages, CreateChatCompl User = user; FunctionCall = functionCall; Functions = functions; - _serializedAdditionalRawData = serializedAdditionalRawData; } /// Initializes a new instance of for deserialization. diff --git a/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/CreateChatCompletionResponseChoice.Serialization.cs b/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/CreateChatCompletionResponseChoice.Serialization.cs index a07ad941d..a994c21a7 100644 --- a/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/CreateChatCompletionResponseChoice.Serialization.cs +++ b/tsp-output/@azure-tools/typespec-csharp/src/Generated/Models/CreateChatCompletionResponseChoice.Serialization.cs @@ -94,7 +94,8 @@ internal static CreateChatCompletionResponseChoice DeserializeCreateChatCompleti } if (property.NameEquals("message"u8)) { - message = ChatCompletionResponseMessage.DeserializeChatCompletionResponseMessage(property.Value, options); + // TODO: use reader APIs instead of going through BinaryData + message = ModelReaderWriter.Read(BinaryData.FromString(property.Value.ToString()), options); continue; } if (property.NameEquals("logprobs"u8)) diff --git a/tsp-output/@azure-tools/typespec-csharp/src/OpenAI.csproj b/tsp-output/@azure-tools/typespec-csharp/src/OpenAI.csproj index 95e032e4e..edd6c0e06 100644 --- a/tsp-output/@azure-tools/typespec-csharp/src/OpenAI.csproj +++ b/tsp-output/@azure-tools/typespec-csharp/src/OpenAI.csproj @@ -10,7 +10,10 @@ - + + + +