From 6a57880b0ecfbe79c5acc5e5a942df3d19494715 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 30 May 2026 02:00:28 +0000 Subject: [PATCH 1/6] fix(csharp): resolve ambiguity in parsing query strings --- src/Stagehand.Tests/TestBase.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Stagehand.Tests/TestBase.cs b/src/Stagehand.Tests/TestBase.cs index 44da81f..9ea9001 100644 --- a/src/Stagehand.Tests/TestBase.cs +++ b/src/Stagehand.Tests/TestBase.cs @@ -39,6 +39,9 @@ internal static bool UrisEqual(Uri uri1, Uri uri2) return Enumerable.SequenceEqual(query1, query2); } + private static readonly char[] _ampersandArray = ['&']; + private static readonly char[] _equalsArray = ['=']; + static SortedDictionary ParseQueryString(string query) { var ret = new SortedDictionary(StringComparer.Ordinal); @@ -46,11 +49,13 @@ static SortedDictionary ParseQueryString(string query) if (string.IsNullOrEmpty(query)) return ret; - var pairs = query.TrimStart('?').Split(['&'], StringSplitOptions.RemoveEmptyEntries); + var pairs = query + .TrimStart('?') + .Split(_ampersandArray, StringSplitOptions.RemoveEmptyEntries); foreach (var pair in pairs) { - var parts = pair.Split(['&'], 2); + var parts = pair.Split(_equalsArray, 2); var key = Uri.UnescapeDataString(parts[0]); var value = parts.Length > 1 ? Uri.UnescapeDataString(parts[1]) : string.Empty; ret[key] = value; From 889f962499019bbe14fbb29e2d5bf6afdf096a99 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 9 Jun 2026 21:01:19 +0000 Subject: [PATCH 2/6] feat: [STG-2090] Add Azure Entra model auth support --- .stats.yml | 4 +- .../Models/Sessions/ModelConfigTest.cs | 1410 +++++ .../Models/Sessions/SessionActParamsTest.cs | 1408 +++++ .../Sessions/SessionExecuteParamsTest.cs | 5050 +++++++++++++---- .../Sessions/SessionExtractParamsTest.cs | 1473 +++++ .../Sessions/SessionObserveParamsTest.cs | 1473 +++++ src/Stagehand/Models/Sessions/ModelConfig.cs | 1092 +++- .../Models/Sessions/SessionActParams.cs | 1050 +++- .../Models/Sessions/SessionExecuteParams.cs | 3909 ++++++++++--- .../Models/Sessions/SessionExtractParams.cs | 1139 +++- .../Models/Sessions/SessionObserveParams.cs | 1139 +++- 11 files changed, 17177 insertions(+), 1970 deletions(-) diff --git a/.stats.yml b/.stats.yml index 15099ca..90ce078 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-c7910965e66e73ad8b65b6cc391d431094b2a6c6577c3e9d82feaa8138e74cff.yml -openapi_spec_hash: 37748bb69c22a9ce721d9b5a5861f964 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-4d0d50b4f18fd74f58aca0b84d6968d1228499f2fa4e5714516f13ff6f820c9d.yml +openapi_spec_hash: f7b1a869f3e412aea4d4bd42467791bb config_hash: 1fb12ae9b478488bc1e56bfbdc210b01 diff --git a/src/Stagehand.Tests/Models/Sessions/ModelConfigTest.cs b/src/Stagehand.Tests/Models/Sessions/ModelConfigTest.cs index e459154..5d910c7 100644 --- a/src/Stagehand.Tests/Models/Sessions/ModelConfigTest.cs +++ b/src/Stagehand.Tests/Models/Sessions/ModelConfigTest.cs @@ -50,6 +50,52 @@ public void VertexModelConfigObjectValidationWorks() value.Validate(); } + [Fact] + public void AzureEntraModelConfigObjectValidationWorks() + { + ModelConfig value = new ModelConfigAzureEntraModelConfigObject() + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + value.Validate(); + } + + [Fact] + public void AzureApiKeyModelConfigObjectValidationWorks() + { + ModelConfig value = new ModelConfigAzureApiKeyModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + value.Validate(); + } + [Fact] public void GenericModelConfigObjectValidationWorks() { @@ -112,6 +158,64 @@ public void VertexModelConfigObjectSerializationRoundtripWorks() Assert.Equal(value, deserialized); } + [Fact] + public void AzureEntraModelConfigObjectSerializationRoundtripWorks() + { + ModelConfig value = new ModelConfigAzureEntraModelConfigObject() + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AzureApiKeyModelConfigObjectSerializationRoundtripWorks() + { + ModelConfig value = new ModelConfigAzureApiKeyModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + [Fact] public void GenericModelConfigObjectSerializationRoundtripWorks() { @@ -1632,6 +1736,1312 @@ public void CopyConstructor_Works() } } +public class ModelConfigAzureEntraModelConfigObjectTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ModelConfigAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + ModelConfigAzureEntraModelConfigObjectAuth expectedAuth = new("x"); + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + ModelConfigAzureEntraModelConfigObjectProviderOptions expectedProviderOptions = new( + new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedAuth, model.Auth); + Assert.Equal(expectedModelName, model.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, model.Provider)); + Assert.Equal(expectedProviderOptions, model.ProviderOptions); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ModelConfigAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ModelConfigAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + ModelConfigAzureEntraModelConfigObjectAuth expectedAuth = new("x"); + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + ModelConfigAzureEntraModelConfigObjectProviderOptions expectedProviderOptions = new( + new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedAuth, deserialized.Auth); + Assert.Equal(expectedModelName, deserialized.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, deserialized.Provider)); + Assert.Equal(expectedProviderOptions, deserialized.ProviderOptions); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new ModelConfigAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ModelConfigAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new ModelConfigAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new ModelConfigAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + BaseUrl = null, + Headers = null, + }; + + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new ModelConfigAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + BaseUrl = null, + Headers = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new ModelConfigAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + ModelConfigAzureEntraModelConfigObject copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class ModelConfigAzureEntraModelConfigObjectAuthTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectAuth { Token = "x" }; + + string expectedToken = "x"; + JsonElement expectedType = JsonSerializer.SerializeToElement("azureEntraId"); + + Assert.Equal(expectedToken, model.Token); + Assert.True(JsonElement.DeepEquals(expectedType, model.Type)); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectAuth { Token = "x" }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectAuth { Token = "x" }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedToken = "x"; + JsonElement expectedType = JsonSerializer.SerializeToElement("azureEntraId"); + + Assert.Equal(expectedToken, deserialized.Token); + Assert.True(JsonElement.DeepEquals(expectedType, deserialized.Type)); + } + + [Fact] + public void Validation_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectAuth { Token = "x" }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectAuth { Token = "x" }; + + ModelConfigAzureEntraModelConfigObjectAuth copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class ModelConfigAzureEntraModelConfigObjectProviderOptionsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure expectedAzure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, model.Azure); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure expectedAzure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, deserialized.Azure); + } + + [Fact] + public void Validation_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + ModelConfigAzureEntraModelConfigObjectProviderOptions copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class ModelConfigAzureEntraModelConfigObjectProviderOptionsAzureTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, model.ApiVersion); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, model.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, model.UseDeploymentBasedUrls); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, deserialized.ApiVersion); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, deserialized.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, deserialized.UseDeploymentBasedUrls); + } + + [Fact] + public void Validation_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure { }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class ModelConfigAzureApiKeyModelConfigObjectTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + ModelConfigAzureApiKeyModelConfigObjectProviderOptions expectedProviderOptions = new( + new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedModelName, model.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, model.Provider)); + Assert.Equal(expectedProviderOptions, model.ProviderOptions); + Assert.Equal(expectedApiKey, model.ApiKey); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + ModelConfigAzureApiKeyModelConfigObjectProviderOptions expectedProviderOptions = new( + new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedModelName, deserialized.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, deserialized.Provider)); + Assert.Equal(expectedProviderOptions, deserialized.ProviderOptions); + Assert.Equal(expectedApiKey, deserialized.ApiKey); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + ApiKey = null, + BaseUrl = null, + Headers = null, + }; + + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + ApiKey = null, + BaseUrl = null, + Headers = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + ModelConfigAzureApiKeyModelConfigObject copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class ModelConfigAzureApiKeyModelConfigObjectProviderOptionsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure expectedAzure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, model.Azure); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure expectedAzure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, deserialized.Azure); + } + + [Fact] + public void Validation_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + ModelConfigAzureApiKeyModelConfigObjectProviderOptions copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzureTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, model.ApiVersion); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, model.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, model.UseDeploymentBasedUrls); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, deserialized.ApiVersion); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, deserialized.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, deserialized.UseDeploymentBasedUrls); + } + + [Fact] + public void Validation_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure { }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure copied = new(model); + + Assert.Equal(model, copied); + } +} + public class ModelConfigGenericModelConfigObjectTest : TestBase { [Fact] diff --git a/src/Stagehand.Tests/Models/Sessions/SessionActParamsTest.cs b/src/Stagehand.Tests/Models/Sessions/SessionActParamsTest.cs index c6a187c..a7f1593 100644 --- a/src/Stagehand.Tests/Models/Sessions/SessionActParamsTest.cs +++ b/src/Stagehand.Tests/Models/Sessions/SessionActParamsTest.cs @@ -1015,6 +1015,52 @@ public void VertexModelConfigObjectValidationWorks() value.Validate(); } + [Fact] + public void AzureEntraModelConfigObjectValidationWorks() + { + Sessions::Model value = new Sessions::AzureEntraModelConfigObject() + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::Azure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + value.Validate(); + } + + [Fact] + public void AzureApiKeyModelConfigObjectValidationWorks() + { + Sessions::Model value = new Sessions::AzureApiKeyModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + value.Validate(); + } + [Fact] public void GenericModelConfigObjectValidationWorks() { @@ -1084,6 +1130,64 @@ public void VertexModelConfigObjectSerializationRoundtripWorks() Assert.Equal(value, deserialized); } + [Fact] + public void AzureEntraModelConfigObjectSerializationRoundtripWorks() + { + Sessions::Model value = new Sessions::AzureEntraModelConfigObject() + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::Azure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AzureApiKeyModelConfigObjectSerializationRoundtripWorks() + { + Sessions::Model value = new Sessions::AzureApiKeyModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + [Fact] public void GenericModelConfigObjectSerializationRoundtripWorks() { @@ -2603,6 +2707,1310 @@ public void CopyConstructor_Works() } } +public class AzureEntraModelConfigObjectTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Sessions::AzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::Azure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + Sessions::AzureEntraModelConfigObjectAuth expectedAuth = new("x"); + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + Sessions::AzureEntraModelConfigObjectProviderOptions expectedProviderOptions = new( + new Sessions::Azure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedAuth, model.Auth); + Assert.Equal(expectedModelName, model.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, model.Provider)); + Assert.Equal(expectedProviderOptions, model.ProviderOptions); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Sessions::AzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::Azure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Sessions::AzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::Azure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + Sessions::AzureEntraModelConfigObjectAuth expectedAuth = new("x"); + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + Sessions::AzureEntraModelConfigObjectProviderOptions expectedProviderOptions = new( + new Sessions::Azure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedAuth, deserialized.Auth); + Assert.Equal(expectedModelName, deserialized.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, deserialized.Provider)); + Assert.Equal(expectedProviderOptions, deserialized.ProviderOptions); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Sessions::AzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::Azure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Sessions::AzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::Azure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new Sessions::AzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::Azure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new Sessions::AzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::Azure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + BaseUrl = null, + Headers = null, + }; + + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new Sessions::AzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::Azure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + BaseUrl = null, + Headers = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new Sessions::AzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::Azure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + Sessions::AzureEntraModelConfigObject copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AzureEntraModelConfigObjectAuthTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Sessions::AzureEntraModelConfigObjectAuth { Token = "x" }; + + string expectedToken = "x"; + JsonElement expectedType = JsonSerializer.SerializeToElement("azureEntraId"); + + Assert.Equal(expectedToken, model.Token); + Assert.True(JsonElement.DeepEquals(expectedType, model.Type)); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Sessions::AzureEntraModelConfigObjectAuth { Token = "x" }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Sessions::AzureEntraModelConfigObjectAuth { Token = "x" }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedToken = "x"; + JsonElement expectedType = JsonSerializer.SerializeToElement("azureEntraId"); + + Assert.Equal(expectedToken, deserialized.Token); + Assert.True(JsonElement.DeepEquals(expectedType, deserialized.Type)); + } + + [Fact] + public void Validation_Works() + { + var model = new Sessions::AzureEntraModelConfigObjectAuth { Token = "x" }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new Sessions::AzureEntraModelConfigObjectAuth { Token = "x" }; + + Sessions::AzureEntraModelConfigObjectAuth copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AzureEntraModelConfigObjectProviderOptionsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Sessions::AzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + Sessions::Azure expectedAzure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, model.Azure); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Sessions::AzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Sessions::AzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + Sessions::Azure expectedAzure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, deserialized.Azure); + } + + [Fact] + public void Validation_Works() + { + var model = new Sessions::AzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new Sessions::AzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + Sessions::AzureEntraModelConfigObjectProviderOptions copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AzureTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Sessions::Azure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, model.ApiVersion); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, model.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, model.UseDeploymentBasedUrls); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Sessions::Azure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Sessions::Azure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, deserialized.ApiVersion); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, deserialized.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, deserialized.UseDeploymentBasedUrls); + } + + [Fact] + public void Validation_Works() + { + var model = new Sessions::Azure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Sessions::Azure { }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new Sessions::Azure { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new Sessions::Azure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new Sessions::Azure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new Sessions::Azure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Sessions::Azure copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AzureApiKeyModelConfigObjectTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + Sessions::AzureApiKeyModelConfigObjectProviderOptions expectedProviderOptions = new( + new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedModelName, model.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, model.Provider)); + Assert.Equal(expectedProviderOptions, model.ProviderOptions); + Assert.Equal(expectedApiKey, model.ApiKey); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + Sessions::AzureApiKeyModelConfigObjectProviderOptions expectedProviderOptions = new( + new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedModelName, deserialized.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, deserialized.Provider)); + Assert.Equal(expectedProviderOptions, deserialized.ProviderOptions); + Assert.Equal(expectedApiKey, deserialized.ApiKey); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + ApiKey = null, + BaseUrl = null, + Headers = null, + }; + + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + ApiKey = null, + BaseUrl = null, + Headers = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + Sessions::AzureApiKeyModelConfigObject copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AzureApiKeyModelConfigObjectProviderOptionsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure expectedAzure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, model.Azure); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure expectedAzure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, deserialized.Azure); + } + + [Fact] + public void Validation_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + Sessions::AzureApiKeyModelConfigObjectProviderOptions copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AzureApiKeyModelConfigObjectProviderOptionsAzureTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, model.ApiVersion); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, model.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, model.UseDeploymentBasedUrls); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, deserialized.ApiVersion); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, deserialized.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, deserialized.UseDeploymentBasedUrls); + } + + [Fact] + public void Validation_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure { }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Sessions::AzureApiKeyModelConfigObjectProviderOptionsAzure copied = new(model); + + Assert.Equal(model, copied); + } +} + public class GenericModelConfigObjectTest : TestBase { [Fact] diff --git a/src/Stagehand.Tests/Models/Sessions/SessionExecuteParamsTest.cs b/src/Stagehand.Tests/Models/Sessions/SessionExecuteParamsTest.cs index 1de9022..7104aea 100644 --- a/src/Stagehand.Tests/Models/Sessions/SessionExecuteParamsTest.cs +++ b/src/Stagehand.Tests/Models/Sessions/SessionExecuteParamsTest.cs @@ -1749,6 +1749,52 @@ public void VertexModelConfigObjectValidationWorks() value.Validate(); } + [Fact] + public void AzureEntraModelConfigObjectValidationWorks() + { + ExecutionModel value = new ExecutionModelAzureEntraModelConfigObject() + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + value.Validate(); + } + + [Fact] + public void AzureApiKeyModelConfigObjectValidationWorks() + { + ExecutionModel value = new ExecutionModelAzureApiKeyModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + value.Validate(); + } + [Fact] public void GenericModelConfigObjectValidationWorks() { @@ -1818,6 +1864,64 @@ public void VertexModelConfigObjectSerializationRoundtripWorks() Assert.Equal(value, deserialized); } + [Fact] + public void AzureEntraModelConfigObjectSerializationRoundtripWorks() + { + ExecutionModel value = new ExecutionModelAzureEntraModelConfigObject() + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AzureApiKeyModelConfigObjectSerializationRoundtripWorks() + { + ExecutionModel value = new ExecutionModelAzureApiKeyModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + [Fact] public void GenericModelConfigObjectSerializationRoundtripWorks() { @@ -3353,29 +3457,49 @@ public void CopyConstructor_Works() } } -public class ExecutionModelGenericModelConfigObjectTest : TestBase +public class ExecutionModelAzureEntraModelConfigObjectTest : TestBase { [Fact] public void FieldRoundtrip_Works() { - var model = new ExecutionModelGenericModelConfigObject + var model = new ExecutionModelAzureEntraModelConfigObject { + Auth = new("x"), ModelName = "openai/gpt-5.4-mini", - ApiKey = "sk-some-openai-api-key", + ProviderOptions = new( + new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, - Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, }; + ExecutionModelAzureEntraModelConfigObjectAuth expectedAuth = new("x"); string expectedModelName = "openai/gpt-5.4-mini"; - string expectedApiKey = "sk-some-openai-api-key"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + ExecutionModelAzureEntraModelConfigObjectProviderOptions expectedProviderOptions = new( + new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; - ApiEnum expectedProvider = - ExecutionModelGenericModelConfigObjectProvider.OpenAI; + Assert.Equal(expectedAuth, model.Auth); Assert.Equal(expectedModelName, model.ModelName); - Assert.Equal(expectedApiKey, model.ApiKey); + Assert.True(JsonElement.DeepEquals(expectedProvider, model.Provider)); + Assert.Equal(expectedProviderOptions, model.ProviderOptions); Assert.Equal(expectedBaseUrl, model.BaseUrl); Assert.NotNull(model.Headers); Assert.Equal(expectedHeaders.Count, model.Headers.Count); @@ -3385,23 +3509,31 @@ public void FieldRoundtrip_Works() Assert.Equal(value, model.Headers[item.Key]); } - Assert.Equal(expectedProvider, model.Provider); } [Fact] public void SerializationRoundtrip_Works() { - var model = new ExecutionModelGenericModelConfigObject + var model = new ExecutionModelAzureEntraModelConfigObject { + Auth = new("x"), ModelName = "openai/gpt-5.4-mini", - ApiKey = "sk-some-openai-api-key", + ProviderOptions = new( + new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, - Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, }; string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( json, ModelBase.SerializerOptions ); @@ -3412,31 +3544,51 @@ public void SerializationRoundtrip_Works() [Fact] public void FieldRoundtripThroughSerialization_Works() { - var model = new ExecutionModelGenericModelConfigObject + var model = new ExecutionModelAzureEntraModelConfigObject { + Auth = new("x"), ModelName = "openai/gpt-5.4-mini", - ApiKey = "sk-some-openai-api-key", + ProviderOptions = new( + new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, - Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, }; string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, ModelBase.SerializerOptions ); Assert.NotNull(deserialized); + ExecutionModelAzureEntraModelConfigObjectAuth expectedAuth = new("x"); string expectedModelName = "openai/gpt-5.4-mini"; - string expectedApiKey = "sk-some-openai-api-key"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + ExecutionModelAzureEntraModelConfigObjectProviderOptions expectedProviderOptions = new( + new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; - ApiEnum expectedProvider = - ExecutionModelGenericModelConfigObjectProvider.OpenAI; + Assert.Equal(expectedAuth, deserialized.Auth); Assert.Equal(expectedModelName, deserialized.ModelName); - Assert.Equal(expectedApiKey, deserialized.ApiKey); + Assert.True(JsonElement.DeepEquals(expectedProvider, deserialized.Provider)); + Assert.Equal(expectedProviderOptions, deserialized.ProviderOptions); Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); Assert.NotNull(deserialized.Headers); Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); @@ -3446,19 +3598,27 @@ public void FieldRoundtripThroughSerialization_Works() Assert.Equal(value, deserialized.Headers[item.Key]); } - Assert.Equal(expectedProvider, deserialized.Provider); } [Fact] public void Validation_Works() { - var model = new ExecutionModelGenericModelConfigObject + var model = new ExecutionModelAzureEntraModelConfigObject { + Auth = new("x"), ModelName = "openai/gpt-5.4-mini", - ApiKey = "sk-some-openai-api-key", + ProviderOptions = new( + new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, - Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, }; model.Validate(); @@ -3467,27 +3627,45 @@ public void Validation_Works() [Fact] public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() { - var model = new ExecutionModelGenericModelConfigObject + var model = new ExecutionModelAzureEntraModelConfigObject { + Auth = new("x"), ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), }; - Assert.Null(model.ApiKey); - Assert.False(model.RawData.ContainsKey("apiKey")); Assert.Null(model.BaseUrl); Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); - Assert.Null(model.Provider); - Assert.False(model.RawData.ContainsKey("provider")); } [Fact] public void OptionalNonNullablePropertiesUnsetValidation_Works() { - var model = new ExecutionModelGenericModelConfigObject + var model = new ExecutionModelAzureEntraModelConfigObject { + Auth = new("x"), ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), }; model.Validate(); @@ -3496,39 +3674,53 @@ public void OptionalNonNullablePropertiesUnsetValidation_Works() [Fact] public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() { - var model = new ExecutionModelGenericModelConfigObject + var model = new ExecutionModelAzureEntraModelConfigObject { + Auth = new("x"), ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), // Null should be interpreted as omitted for these properties - ApiKey = null, BaseUrl = null, Headers = null, - Provider = null, }; - Assert.Null(model.ApiKey); - Assert.False(model.RawData.ContainsKey("apiKey")); Assert.Null(model.BaseUrl); Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); - Assert.Null(model.Provider); - Assert.False(model.RawData.ContainsKey("provider")); } [Fact] public void OptionalNonNullablePropertiesSetToNullValidation_Works() { - var model = new ExecutionModelGenericModelConfigObject + var model = new ExecutionModelAzureEntraModelConfigObject { + Auth = new("x"), ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), // Null should be interpreted as omitted for these properties - ApiKey = null, BaseUrl = null, Headers = null, - Provider = null, }; model.Validate(); @@ -3537,328 +3729,437 @@ public void OptionalNonNullablePropertiesSetToNullValidation_Works() [Fact] public void CopyConstructor_Works() { - var model = new ExecutionModelGenericModelConfigObject + var model = new ExecutionModelAzureEntraModelConfigObject { + Auth = new("x"), ModelName = "openai/gpt-5.4-mini", - ApiKey = "sk-some-openai-api-key", + ProviderOptions = new( + new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, - Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, }; - ExecutionModelGenericModelConfigObject copied = new(model); + ExecutionModelAzureEntraModelConfigObject copied = new(model); Assert.Equal(model, copied); } } -public class ExecutionModelGenericModelConfigObjectProviderTest : TestBase +public class ExecutionModelAzureEntraModelConfigObjectAuthTest : TestBase { - [Theory] - [InlineData(ExecutionModelGenericModelConfigObjectProvider.OpenAI)] - [InlineData(ExecutionModelGenericModelConfigObjectProvider.Anthropic)] - [InlineData(ExecutionModelGenericModelConfigObjectProvider.Google)] - [InlineData(ExecutionModelGenericModelConfigObjectProvider.Microsoft)] - [InlineData(ExecutionModelGenericModelConfigObjectProvider.Bedrock)] - public void Validation_Works(ExecutionModelGenericModelConfigObjectProvider rawValue) + [Fact] + public void FieldRoundtrip_Works() { - // force implicit conversion because Theory can't do that for us - ApiEnum value = rawValue; - value.Validate(); + var model = new ExecutionModelAzureEntraModelConfigObjectAuth { Token = "x" }; + + string expectedToken = "x"; + JsonElement expectedType = JsonSerializer.SerializeToElement("azureEntraId"); + + Assert.Equal(expectedToken, model.Token); + Assert.True(JsonElement.DeepEquals(expectedType, model.Type)); } [Fact] - public void InvalidEnumValidationThrows_Works() + public void SerializationRoundtrip_Works() { - var value = JsonSerializer.Deserialize< - ApiEnum - >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + var model = new ExecutionModelAzureEntraModelConfigObjectAuth { Token = "x" }; - Assert.NotNull(value); - Assert.Throws(() => value.Validate()); + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); } - [Theory] - [InlineData(ExecutionModelGenericModelConfigObjectProvider.OpenAI)] - [InlineData(ExecutionModelGenericModelConfigObjectProvider.Anthropic)] - [InlineData(ExecutionModelGenericModelConfigObjectProvider.Google)] - [InlineData(ExecutionModelGenericModelConfigObjectProvider.Microsoft)] - [InlineData(ExecutionModelGenericModelConfigObjectProvider.Bedrock)] - public void SerializationRoundtrip_Works( - ExecutionModelGenericModelConfigObjectProvider rawValue - ) + [Fact] + public void FieldRoundtripThroughSerialization_Works() { - // force implicit conversion because Theory can't do that for us - ApiEnum value = rawValue; + var model = new ExecutionModelAzureEntraModelConfigObjectAuth { Token = "x" }; - string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize< - ApiEnum - >(json, ModelBase.SerializerOptions); + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); - Assert.Equal(value, deserialized); + string expectedToken = "x"; + JsonElement expectedType = JsonSerializer.SerializeToElement("azureEntraId"); + + Assert.Equal(expectedToken, deserialized.Token); + Assert.True(JsonElement.DeepEquals(expectedType, deserialized.Type)); } [Fact] - public void InvalidEnumSerializationRoundtrip_Works() + public void Validation_Works() { - var value = JsonSerializer.Deserialize< - ApiEnum - >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); - string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize< - ApiEnum - >(json, ModelBase.SerializerOptions); - - Assert.Equal(value, deserialized); - } -} + var model = new ExecutionModelAzureEntraModelConfigObjectAuth { Token = "x" }; -public class ModeTest : TestBase -{ - [Theory] - [InlineData(Mode.Dom)] - [InlineData(Mode.Hybrid)] - [InlineData(Mode.Cua)] - public void Validation_Works(Mode rawValue) - { - // force implicit conversion because Theory can't do that for us - ApiEnum value = rawValue; - value.Validate(); + model.Validate(); } [Fact] - public void InvalidEnumValidationThrows_Works() + public void CopyConstructor_Works() { - var value = JsonSerializer.Deserialize>( - JsonSerializer.SerializeToElement("invalid value"), - ModelBase.SerializerOptions - ); + var model = new ExecutionModelAzureEntraModelConfigObjectAuth { Token = "x" }; - Assert.NotNull(value); - Assert.Throws(() => value.Validate()); + ExecutionModelAzureEntraModelConfigObjectAuth copied = new(model); + + Assert.Equal(model, copied); } +} - [Theory] - [InlineData(Mode.Dom)] - [InlineData(Mode.Hybrid)] - [InlineData(Mode.Cua)] - public void SerializationRoundtrip_Works(Mode rawValue) +public class ExecutionModelAzureEntraModelConfigObjectProviderOptionsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() { - // force implicit conversion because Theory can't do that for us - ApiEnum value = rawValue; + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; - string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize>( - json, - ModelBase.SerializerOptions - ); + ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure expectedAzure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; - Assert.Equal(value, deserialized); + Assert.Equal(expectedAzure, model.Azure); } [Fact] - public void InvalidEnumSerializationRoundtrip_Works() + public void SerializationRoundtrip_Works() { - var value = JsonSerializer.Deserialize>( - JsonSerializer.SerializeToElement("invalid value"), - ModelBase.SerializerOptions - ); - string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize>( - json, - ModelBase.SerializerOptions - ); + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; - Assert.Equal(value, deserialized); + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); } -} -public class AgentConfigModelTest : TestBase -{ [Fact] - public void VertexModelConfigObjectValidationWorks() + public void FieldRoundtripThroughSerialization_Works() { - AgentConfigModel value = new AgentConfigModelVertexModelConfigObject() + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptions { - Auth = new() + Azure = new() { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }, - ModelName = "openai/gpt-5.4-mini", - ProviderOptions = new( - new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() - { - Location = "us-central1", - Project = "my-gcp-project", - BaseUrl = "https://example.com", - Headers = new Dictionary() { { "foo", "string" } }, - } - ), - ApiKey = "sk-some-openai-api-key", - BaseUrl = "https://api.openai.com/v1", - Headers = new Dictionary() { { "foo", "string" } }, }; - value.Validate(); - } - [Fact] - public void GenericModelConfigObjectValidationWorks() - { - AgentConfigModel value = new AgentConfigModelGenericModelConfigObject() + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure expectedAzure = new() { - ModelName = "openai/gpt-5.4-mini", - ApiKey = "sk-some-openai-api-key", - BaseUrl = "https://api.openai.com/v1", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, - Provider = AgentConfigModelGenericModelConfigObjectProvider.OpenAI, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; - value.Validate(); + + Assert.Equal(expectedAzure, deserialized.Azure); } [Fact] - public void StringValidationWorks() + public void Validation_Works() { - AgentConfigModel value = "string"; - value.Validate(); + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + model.Validate(); } [Fact] - public void VertexModelConfigObjectSerializationRoundtripWorks() + public void CopyConstructor_Works() { - AgentConfigModel value = new AgentConfigModelVertexModelConfigObject() + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptions { - Auth = new() + Azure = new() { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }, - ModelName = "openai/gpt-5.4-mini", - ProviderOptions = new( - new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() - { - Location = "us-central1", - Project = "my-gcp-project", - BaseUrl = "https://example.com", - Headers = new Dictionary() { { "foo", "string" } }, - } - ), - ApiKey = "sk-some-openai-api-key", - BaseUrl = "https://api.openai.com/v1", - Headers = new Dictionary() { { "foo", "string" } }, }; - string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); - Assert.Equal(value, deserialized); + ExecutionModelAzureEntraModelConfigObjectProviderOptions copied = new(model); + + Assert.Equal(model, copied); } +} +public class ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzureTest : TestBase +{ [Fact] - public void GenericModelConfigObjectSerializationRoundtripWorks() + public void FieldRoundtrip_Works() { - AgentConfigModel value = new AgentConfigModelGenericModelConfigObject() + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure { - ModelName = "openai/gpt-5.4-mini", - ApiKey = "sk-some-openai-api-key", - BaseUrl = "https://api.openai.com/v1", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, - Provider = AgentConfigModelGenericModelConfigObjectProvider.OpenAI, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; - string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); - Assert.Equal(value, deserialized); + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, model.ApiVersion); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, model.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, model.UseDeploymentBasedUrls); } [Fact] - public void StringSerializationRoundtripWorks() + public void SerializationRoundtrip_Works() { - AgentConfigModel value = "string"; - string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; - Assert.Equal(value, deserialized); + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); } -} -public class AgentConfigModelVertexModelConfigObjectTest : TestBase -{ [Fact] - public void FieldRoundtrip_Works() + public void FieldRoundtripThroughSerialization_Works() { - var model = new AgentConfigModelVertexModelConfigObject + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, deserialized.ApiVersion); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, deserialized.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, deserialized.UseDeploymentBasedUrls); + } + + [Fact] + public void Validation_Works() + { + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure { }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class ExecutionModelAzureApiKeyModelConfigObjectTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ExecutionModelAzureApiKeyModelConfigObject { - Auth = new() - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", - }, ModelName = "openai/gpt-5.4-mini", ProviderOptions = new( - new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, } ), ApiKey = "sk-some-openai-api-key", @@ -3866,42 +4167,22 @@ public void FieldRoundtrip_Works() Headers = new Dictionary() { { "foo", "string" } }, }; - AgentConfigModelVertexModelConfigObjectAuth expectedAuth = new() - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", - }; string expectedModelName = "openai/gpt-5.4-mini"; - JsonElement expectedProvider = JsonSerializer.SerializeToElement("vertex"); - AgentConfigModelVertexModelConfigObjectProviderOptions expectedProviderOptions = new( - new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + ExecutionModelAzureApiKeyModelConfigObjectProviderOptions expectedProviderOptions = new( + new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, } ); string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; - Assert.Equal(expectedAuth, model.Auth); Assert.Equal(expectedModelName, model.ModelName); Assert.True(JsonElement.DeepEquals(expectedProvider, model.Provider)); Assert.Equal(expectedProviderOptions, model.ProviderOptions); @@ -3920,37 +4201,17 @@ public void FieldRoundtrip_Works() [Fact] public void SerializationRoundtrip_Works() { - var model = new AgentConfigModelVertexModelConfigObject + var model = new ExecutionModelAzureApiKeyModelConfigObject { - Auth = new() - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", - }, ModelName = "openai/gpt-5.4-mini", ProviderOptions = new( - new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, } ), ApiKey = "sk-some-openai-api-key", @@ -3959,7 +4220,7 @@ public void SerializationRoundtrip_Works() }; string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( json, ModelBase.SerializerOptions ); @@ -3970,37 +4231,17 @@ public void SerializationRoundtrip_Works() [Fact] public void FieldRoundtripThroughSerialization_Works() { - var model = new AgentConfigModelVertexModelConfigObject + var model = new ExecutionModelAzureApiKeyModelConfigObject { - Auth = new() - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", - }, ModelName = "openai/gpt-5.4-mini", ProviderOptions = new( - new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, } ), ApiKey = "sk-some-openai-api-key", @@ -4009,48 +4250,28 @@ public void FieldRoundtripThroughSerialization_Works() }; string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( + var deserialized = JsonSerializer.Deserialize( element, ModelBase.SerializerOptions ); Assert.NotNull(deserialized); - AgentConfigModelVertexModelConfigObjectAuth expectedAuth = new() - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", - }; string expectedModelName = "openai/gpt-5.4-mini"; - JsonElement expectedProvider = JsonSerializer.SerializeToElement("vertex"); - AgentConfigModelVertexModelConfigObjectProviderOptions expectedProviderOptions = new( - new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + ExecutionModelAzureApiKeyModelConfigObjectProviderOptions expectedProviderOptions = new( + new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, } ); string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; - Assert.Equal(expectedAuth, deserialized.Auth); Assert.Equal(expectedModelName, deserialized.ModelName); Assert.True(JsonElement.DeepEquals(expectedProvider, deserialized.Provider)); Assert.Equal(expectedProviderOptions, deserialized.ProviderOptions); @@ -4069,37 +4290,17 @@ public void FieldRoundtripThroughSerialization_Works() [Fact] public void Validation_Works() { - var model = new AgentConfigModelVertexModelConfigObject + var model = new ExecutionModelAzureApiKeyModelConfigObject { - Auth = new() - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", - }, ModelName = "openai/gpt-5.4-mini", ProviderOptions = new( - new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, } ), ApiKey = "sk-some-openai-api-key", @@ -4113,37 +4314,17 @@ public void Validation_Works() [Fact] public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() { - var model = new AgentConfigModelVertexModelConfigObject + var model = new ExecutionModelAzureApiKeyModelConfigObject { - Auth = new() - { - Credentials = new() + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", - }, - ModelName = "openai/gpt-5.4-mini", - ProviderOptions = new( - new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() - { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, } ), }; @@ -4159,37 +4340,17 @@ public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() [Fact] public void OptionalNonNullablePropertiesUnsetValidation_Works() { - var model = new AgentConfigModelVertexModelConfigObject + var model = new ExecutionModelAzureApiKeyModelConfigObject { - Auth = new() - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", - }, ModelName = "openai/gpt-5.4-mini", ProviderOptions = new( - new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, } ), }; @@ -4200,37 +4361,17 @@ public void OptionalNonNullablePropertiesUnsetValidation_Works() [Fact] public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() { - var model = new AgentConfigModelVertexModelConfigObject + var model = new ExecutionModelAzureApiKeyModelConfigObject { - Auth = new() - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", - }, ModelName = "openai/gpt-5.4-mini", ProviderOptions = new( - new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, } ), @@ -4251,37 +4392,17 @@ public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() [Fact] public void OptionalNonNullablePropertiesSetToNullValidation_Works() { - var model = new AgentConfigModelVertexModelConfigObject + var model = new ExecutionModelAzureApiKeyModelConfigObject { - Auth = new() - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", - }, ModelName = "openai/gpt-5.4-mini", ProviderOptions = new( - new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, } ), @@ -4297,37 +4418,17 @@ public void OptionalNonNullablePropertiesSetToNullValidation_Works() [Fact] public void CopyConstructor_Works() { - var model = new AgentConfigModelVertexModelConfigObject + var model = new ExecutionModelAzureApiKeyModelConfigObject { - Auth = new() - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", - }, ModelName = "openai/gpt-5.4-mini", ProviderOptions = new( - new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, } ), ApiKey = "sk-some-openai-api-key", @@ -4335,93 +4436,62 @@ public void CopyConstructor_Works() Headers = new Dictionary() { { "foo", "string" } }, }; - AgentConfigModelVertexModelConfigObject copied = new(model); + ExecutionModelAzureApiKeyModelConfigObject copied = new(model); Assert.Equal(model, copied); } } -public class AgentConfigModelVertexModelConfigObjectAuthTest : TestBase +public class ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsTest : TestBase { [Fact] public void FieldRoundtrip_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuth + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptions { - Credentials = new() + Azure = new() { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", }; - AgentConfigModelVertexModelConfigObjectAuthCredentials expectedCredentials = new() + ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure expectedAzure = new() { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; - JsonElement expectedType = JsonSerializer.SerializeToElement("googleServiceAccount"); - string expectedProjectID = "projectId"; - AgentConfigModelVertexModelConfigObjectAuthScopes expectedScopes = "string"; - string expectedUniverseDomain = "universeDomain"; - Assert.Equal(expectedCredentials, model.Credentials); - Assert.True(JsonElement.DeepEquals(expectedType, model.Type)); - Assert.Equal(expectedProjectID, model.ProjectID); - Assert.Equal(expectedScopes, model.Scopes); - Assert.Equal(expectedUniverseDomain, model.UniverseDomain); + Assert.Equal(expectedAzure, model.Azure); } [Fact] public void SerializationRoundtrip_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuth + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptions { - Credentials = new() + Azure = new() { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", }; string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - json, - ModelBase.SerializerOptions - ); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); Assert.Equal(model, deserialized); } @@ -4429,198 +4499,51 @@ public void SerializationRoundtrip_Works() [Fact] public void FieldRoundtripThroughSerialization_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuth + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptions { - Credentials = new() + Azure = new() { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", }; string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); Assert.NotNull(deserialized); - AgentConfigModelVertexModelConfigObjectAuthCredentials expectedCredentials = new() + ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure expectedAzure = new() { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; - JsonElement expectedType = JsonSerializer.SerializeToElement("googleServiceAccount"); - string expectedProjectID = "projectId"; - AgentConfigModelVertexModelConfigObjectAuthScopes expectedScopes = "string"; - string expectedUniverseDomain = "universeDomain"; - Assert.Equal(expectedCredentials, deserialized.Credentials); - Assert.True(JsonElement.DeepEquals(expectedType, deserialized.Type)); - Assert.Equal(expectedProjectID, deserialized.ProjectID); - Assert.Equal(expectedScopes, deserialized.Scopes); - Assert.Equal(expectedUniverseDomain, deserialized.UniverseDomain); + Assert.Equal(expectedAzure, deserialized.Azure); } [Fact] public void Validation_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuth + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptions { - Credentials = new() + Azure = new() { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", - }; - - model.Validate(); - } - - [Fact] - public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() - { - var model = new AgentConfigModelVertexModelConfigObjectAuth - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - }; - - Assert.Null(model.ProjectID); - Assert.False(model.RawData.ContainsKey("projectId")); - Assert.Null(model.Scopes); - Assert.False(model.RawData.ContainsKey("scopes")); - Assert.Null(model.UniverseDomain); - Assert.False(model.RawData.ContainsKey("universeDomain")); - } - - [Fact] - public void OptionalNonNullablePropertiesUnsetValidation_Works() - { - var model = new AgentConfigModelVertexModelConfigObjectAuth - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - }; - - model.Validate(); - } - - [Fact] - public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() - { - var model = new AgentConfigModelVertexModelConfigObjectAuth - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - - // Null should be interpreted as omitted for these properties - ProjectID = null, - Scopes = null, - UniverseDomain = null, - }; - - Assert.Null(model.ProjectID); - Assert.False(model.RawData.ContainsKey("projectId")); - Assert.Null(model.Scopes); - Assert.False(model.RawData.ContainsKey("scopes")); - Assert.Null(model.UniverseDomain); - Assert.False(model.RawData.ContainsKey("universeDomain")); - } - - [Fact] - public void OptionalNonNullablePropertiesSetToNullValidation_Works() - { - var model = new AgentConfigModelVertexModelConfigObjectAuth - { - Credentials = new() - { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", - }, - - // Null should be interpreted as omitted for these properties - ProjectID = null, - Scopes = null, - UniverseDomain = null, }; model.Validate(); @@ -4629,100 +4552,73 @@ public void OptionalNonNullablePropertiesSetToNullValidation_Works() [Fact] public void CopyConstructor_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuth + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptions { - Credentials = new() + Azure = new() { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }, - ProjectID = "projectId", - Scopes = "string", - UniverseDomain = "universeDomain", }; - AgentConfigModelVertexModelConfigObjectAuth copied = new(model); + ExecutionModelAzureApiKeyModelConfigObjectProviderOptions copied = new(model); Assert.Equal(model, copied); } } -public class AgentConfigModelVertexModelConfigObjectAuthCredentialsTest : TestBase +public class ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzureTest : TestBase { [Fact] public void FieldRoundtrip_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; - string expectedClientEmail = "client_email"; - string expectedPrivateKey = "private_key"; - string expectedAuthProviderX509CertUrl = "https://example.com"; - string expectedAuthUri = "https://example.com"; - string expectedClientID = "client_id"; - string expectedClientX509CertUrl = "https://example.com"; - string expectedPrivateKeyID = "private_key_id"; - string expectedProjectID = "project_id"; - string expectedTokenUri = "https://example.com"; - ApiEnum expectedType = - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount; - string expectedUniverseDomain = "universe_domain"; + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; - Assert.Equal(expectedClientEmail, model.ClientEmail); - Assert.Equal(expectedPrivateKey, model.PrivateKey); - Assert.Equal(expectedAuthProviderX509CertUrl, model.AuthProviderX509CertUrl); - Assert.Equal(expectedAuthUri, model.AuthUri); - Assert.Equal(expectedClientID, model.ClientID); - Assert.Equal(expectedClientX509CertUrl, model.ClientX509CertUrl); - Assert.Equal(expectedPrivateKeyID, model.PrivateKeyID); - Assert.Equal(expectedProjectID, model.ProjectID); - Assert.Equal(expectedTokenUri, model.TokenUri); - Assert.Equal(expectedType, model.Type); - Assert.Equal(expectedUniverseDomain, model.UniverseDomain); + Assert.Equal(expectedApiVersion, model.ApiVersion); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, model.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, model.UseDeploymentBasedUrls); } [Fact] public void SerializationRoundtrip_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); var deserialized = - JsonSerializer.Deserialize( + JsonSerializer.Deserialize( json, ModelBase.SerializerOptions ); @@ -4733,71 +4629,53 @@ public void SerializationRoundtrip_Works() [Fact] public void FieldRoundtripThroughSerialization_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); var deserialized = - JsonSerializer.Deserialize( + JsonSerializer.Deserialize( element, ModelBase.SerializerOptions ); Assert.NotNull(deserialized); - string expectedClientEmail = "client_email"; - string expectedPrivateKey = "private_key"; - string expectedAuthProviderX509CertUrl = "https://example.com"; - string expectedAuthUri = "https://example.com"; - string expectedClientID = "client_id"; - string expectedClientX509CertUrl = "https://example.com"; - string expectedPrivateKeyID = "private_key_id"; - string expectedProjectID = "project_id"; - string expectedTokenUri = "https://example.com"; - ApiEnum expectedType = - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount; - string expectedUniverseDomain = "universe_domain"; + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; - Assert.Equal(expectedClientEmail, deserialized.ClientEmail); - Assert.Equal(expectedPrivateKey, deserialized.PrivateKey); - Assert.Equal(expectedAuthProviderX509CertUrl, deserialized.AuthProviderX509CertUrl); - Assert.Equal(expectedAuthUri, deserialized.AuthUri); - Assert.Equal(expectedClientID, deserialized.ClientID); - Assert.Equal(expectedClientX509CertUrl, deserialized.ClientX509CertUrl); - Assert.Equal(expectedPrivateKeyID, deserialized.PrivateKeyID); - Assert.Equal(expectedProjectID, deserialized.ProjectID); - Assert.Equal(expectedTokenUri, deserialized.TokenUri); - Assert.Equal(expectedType, deserialized.Type); - Assert.Equal(expectedUniverseDomain, deserialized.UniverseDomain); + Assert.Equal(expectedApiVersion, deserialized.ApiVersion); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, deserialized.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, deserialized.UseDeploymentBasedUrls); } [Fact] public void Validation_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; model.Validate(); @@ -4806,39 +4684,222 @@ public void Validation_Works() [Fact] public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure { }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure { - ClientEmail = "client_email", - PrivateKey = "private_key", + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, }; - Assert.Null(model.AuthProviderX509CertUrl); - Assert.False(model.RawData.ContainsKey("auth_provider_x509_cert_url")); - Assert.Null(model.AuthUri); - Assert.False(model.RawData.ContainsKey("auth_uri")); - Assert.Null(model.ClientID); - Assert.False(model.RawData.ContainsKey("client_id")); - Assert.Null(model.ClientX509CertUrl); - Assert.False(model.RawData.ContainsKey("client_x509_cert_url")); - Assert.Null(model.PrivateKeyID); - Assert.False(model.RawData.ContainsKey("private_key_id")); - Assert.Null(model.ProjectID); - Assert.False(model.RawData.ContainsKey("project_id")); - Assert.Null(model.TokenUri); - Assert.False(model.RawData.ContainsKey("token_uri")); - Assert.Null(model.Type); - Assert.False(model.RawData.ContainsKey("type")); - Assert.Null(model.UniverseDomain); - Assert.False(model.RawData.ContainsKey("universe_domain")); + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class ExecutionModelGenericModelConfigObjectTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new ExecutionModelGenericModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, + }; + + string expectedModelName = "openai/gpt-5.4-mini"; + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum expectedProvider = + ExecutionModelGenericModelConfigObjectProvider.OpenAI; + + Assert.Equal(expectedModelName, model.ModelName); + Assert.Equal(expectedApiKey, model.ApiKey); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + Assert.Equal(expectedProvider, model.Provider); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new ExecutionModelGenericModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new ExecutionModelGenericModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedModelName = "openai/gpt-5.4-mini"; + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum expectedProvider = + ExecutionModelGenericModelConfigObjectProvider.OpenAI; + + Assert.Equal(expectedModelName, deserialized.ModelName); + Assert.Equal(expectedApiKey, deserialized.ApiKey); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + Assert.Equal(expectedProvider, deserialized.Provider); + } + + [Fact] + public void Validation_Works() + { + var model = new ExecutionModelGenericModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new ExecutionModelGenericModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + }; + + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.Provider); + Assert.False(model.RawData.ContainsKey("provider")); } [Fact] public void OptionalNonNullablePropertiesUnsetValidation_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + var model = new ExecutionModelGenericModelConfigObject { - ClientEmail = "client_email", - PrivateKey = "private_key", + ModelName = "openai/gpt-5.4-mini", }; model.Validate(); @@ -4847,237 +4908,2983 @@ public void OptionalNonNullablePropertiesUnsetValidation_Works() [Fact] public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + var model = new ExecutionModelGenericModelConfigObject { - ClientEmail = "client_email", - PrivateKey = "private_key", + ModelName = "openai/gpt-5.4-mini", // Null should be interpreted as omitted for these properties - AuthProviderX509CertUrl = null, - AuthUri = null, - ClientID = null, - ClientX509CertUrl = null, - PrivateKeyID = null, - ProjectID = null, - TokenUri = null, - Type = null, - UniverseDomain = null, + ApiKey = null, + BaseUrl = null, + Headers = null, + Provider = null, }; - Assert.Null(model.AuthProviderX509CertUrl); - Assert.False(model.RawData.ContainsKey("auth_provider_x509_cert_url")); - Assert.Null(model.AuthUri); - Assert.False(model.RawData.ContainsKey("auth_uri")); - Assert.Null(model.ClientID); - Assert.False(model.RawData.ContainsKey("client_id")); - Assert.Null(model.ClientX509CertUrl); - Assert.False(model.RawData.ContainsKey("client_x509_cert_url")); - Assert.Null(model.PrivateKeyID); - Assert.False(model.RawData.ContainsKey("private_key_id")); - Assert.Null(model.ProjectID); - Assert.False(model.RawData.ContainsKey("project_id")); - Assert.Null(model.TokenUri); - Assert.False(model.RawData.ContainsKey("token_uri")); - Assert.Null(model.Type); - Assert.False(model.RawData.ContainsKey("type")); - Assert.Null(model.UniverseDomain); - Assert.False(model.RawData.ContainsKey("universe_domain")); + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.Provider); + Assert.False(model.RawData.ContainsKey("provider")); } [Fact] public void OptionalNonNullablePropertiesSetToNullValidation_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + var model = new ExecutionModelGenericModelConfigObject { - ClientEmail = "client_email", + ModelName = "openai/gpt-5.4-mini", + + // Null should be interpreted as omitted for these properties + ApiKey = null, + BaseUrl = null, + Headers = null, + Provider = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new ExecutionModelGenericModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, + }; + + ExecutionModelGenericModelConfigObject copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class ExecutionModelGenericModelConfigObjectProviderTest : TestBase +{ + [Theory] + [InlineData(ExecutionModelGenericModelConfigObjectProvider.OpenAI)] + [InlineData(ExecutionModelGenericModelConfigObjectProvider.Anthropic)] + [InlineData(ExecutionModelGenericModelConfigObjectProvider.Google)] + [InlineData(ExecutionModelGenericModelConfigObjectProvider.Microsoft)] + [InlineData(ExecutionModelGenericModelConfigObjectProvider.Bedrock)] + public void Validation_Works(ExecutionModelGenericModelConfigObjectProvider rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ExecutionModelGenericModelConfigObjectProvider.OpenAI)] + [InlineData(ExecutionModelGenericModelConfigObjectProvider.Anthropic)] + [InlineData(ExecutionModelGenericModelConfigObjectProvider.Google)] + [InlineData(ExecutionModelGenericModelConfigObjectProvider.Microsoft)] + [InlineData(ExecutionModelGenericModelConfigObjectProvider.Bedrock)] + public void SerializationRoundtrip_Works( + ExecutionModelGenericModelConfigObjectProvider rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class ModeTest : TestBase +{ + [Theory] + [InlineData(Mode.Dom)] + [InlineData(Mode.Hybrid)] + [InlineData(Mode.Cua)] + public void Validation_Works(Mode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.SerializeToElement("invalid value"), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Mode.Dom)] + [InlineData(Mode.Hybrid)] + [InlineData(Mode.Cua)] + public void SerializationRoundtrip_Works(Mode rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.SerializeToElement("invalid value"), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize>( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class AgentConfigModelTest : TestBase +{ + [Fact] + public void VertexModelConfigObjectValidationWorks() + { + AgentConfigModel value = new AgentConfigModelVertexModelConfigObject() + { + Auth = new() + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }, + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + value.Validate(); + } + + [Fact] + public void AzureEntraModelConfigObjectValidationWorks() + { + AgentConfigModel value = new AgentConfigModelAzureEntraModelConfigObject() + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + value.Validate(); + } + + [Fact] + public void AzureApiKeyModelConfigObjectValidationWorks() + { + AgentConfigModel value = new AgentConfigModelAzureApiKeyModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + value.Validate(); + } + + [Fact] + public void GenericModelConfigObjectValidationWorks() + { + AgentConfigModel value = new AgentConfigModelGenericModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + Provider = AgentConfigModelGenericModelConfigObjectProvider.OpenAI, + }; + value.Validate(); + } + + [Fact] + public void StringValidationWorks() + { + AgentConfigModel value = "string"; + value.Validate(); + } + + [Fact] + public void VertexModelConfigObjectSerializationRoundtripWorks() + { + AgentConfigModel value = new AgentConfigModelVertexModelConfigObject() + { + Auth = new() + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }, + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AzureEntraModelConfigObjectSerializationRoundtripWorks() + { + AgentConfigModel value = new AgentConfigModelAzureEntraModelConfigObject() + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AzureApiKeyModelConfigObjectSerializationRoundtripWorks() + { + AgentConfigModel value = new AgentConfigModelAzureApiKeyModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void GenericModelConfigObjectSerializationRoundtripWorks() + { + AgentConfigModel value = new AgentConfigModelGenericModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + Provider = AgentConfigModelGenericModelConfigObjectProvider.OpenAI, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void StringSerializationRoundtripWorks() + { + AgentConfigModel value = "string"; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class AgentConfigModelVertexModelConfigObjectTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AgentConfigModelVertexModelConfigObject + { + Auth = new() + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }, + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + AgentConfigModelVertexModelConfigObjectAuth expectedAuth = new() + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }; + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("vertex"); + AgentConfigModelVertexModelConfigObjectProviderOptions expectedProviderOptions = new( + new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + } + ); + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedAuth, model.Auth); + Assert.Equal(expectedModelName, model.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, model.Provider)); + Assert.Equal(expectedProviderOptions, model.ProviderOptions); + Assert.Equal(expectedApiKey, model.ApiKey); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AgentConfigModelVertexModelConfigObject + { + Auth = new() + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }, + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AgentConfigModelVertexModelConfigObject + { + Auth = new() + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }, + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + AgentConfigModelVertexModelConfigObjectAuth expectedAuth = new() + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }; + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("vertex"); + AgentConfigModelVertexModelConfigObjectProviderOptions expectedProviderOptions = new( + new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + } + ); + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedAuth, deserialized.Auth); + Assert.Equal(expectedModelName, deserialized.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, deserialized.Provider)); + Assert.Equal(expectedProviderOptions, deserialized.ProviderOptions); + Assert.Equal(expectedApiKey, deserialized.ApiKey); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new AgentConfigModelVertexModelConfigObject + { + Auth = new() + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }, + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new AgentConfigModelVertexModelConfigObject + { + Auth = new() + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }, + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + } + ), + }; + + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new AgentConfigModelVertexModelConfigObject + { + Auth = new() + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }, + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + } + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new AgentConfigModelVertexModelConfigObject + { + Auth = new() + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }, + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + } + ), + + // Null should be interpreted as omitted for these properties + ApiKey = null, + BaseUrl = null, + Headers = null, + }; + + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new AgentConfigModelVertexModelConfigObject + { + Auth = new() + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }, + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + } + ), + + // Null should be interpreted as omitted for these properties + ApiKey = null, + BaseUrl = null, + Headers = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new AgentConfigModelVertexModelConfigObject + { + Auth = new() + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }, + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + AgentConfigModelVertexModelConfigObject copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AgentConfigModelVertexModelConfigObjectAuthTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuth + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }; + + AgentConfigModelVertexModelConfigObjectAuthCredentials expectedCredentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }; + JsonElement expectedType = JsonSerializer.SerializeToElement("googleServiceAccount"); + string expectedProjectID = "projectId"; + AgentConfigModelVertexModelConfigObjectAuthScopes expectedScopes = "string"; + string expectedUniverseDomain = "universeDomain"; + + Assert.Equal(expectedCredentials, model.Credentials); + Assert.True(JsonElement.DeepEquals(expectedType, model.Type)); + Assert.Equal(expectedProjectID, model.ProjectID); + Assert.Equal(expectedScopes, model.Scopes); + Assert.Equal(expectedUniverseDomain, model.UniverseDomain); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuth + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuth + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + AgentConfigModelVertexModelConfigObjectAuthCredentials expectedCredentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }; + JsonElement expectedType = JsonSerializer.SerializeToElement("googleServiceAccount"); + string expectedProjectID = "projectId"; + AgentConfigModelVertexModelConfigObjectAuthScopes expectedScopes = "string"; + string expectedUniverseDomain = "universeDomain"; + + Assert.Equal(expectedCredentials, deserialized.Credentials); + Assert.True(JsonElement.DeepEquals(expectedType, deserialized.Type)); + Assert.Equal(expectedProjectID, deserialized.ProjectID); + Assert.Equal(expectedScopes, deserialized.Scopes); + Assert.Equal(expectedUniverseDomain, deserialized.UniverseDomain); + } + + [Fact] + public void Validation_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuth + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuth + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + }; + + Assert.Null(model.ProjectID); + Assert.False(model.RawData.ContainsKey("projectId")); + Assert.Null(model.Scopes); + Assert.False(model.RawData.ContainsKey("scopes")); + Assert.Null(model.UniverseDomain); + Assert.False(model.RawData.ContainsKey("universeDomain")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuth + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuth + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + + // Null should be interpreted as omitted for these properties + ProjectID = null, + Scopes = null, + UniverseDomain = null, + }; + + Assert.Null(model.ProjectID); + Assert.False(model.RawData.ContainsKey("projectId")); + Assert.Null(model.Scopes); + Assert.False(model.RawData.ContainsKey("scopes")); + Assert.Null(model.UniverseDomain); + Assert.False(model.RawData.ContainsKey("universeDomain")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuth + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + + // Null should be interpreted as omitted for these properties + ProjectID = null, + Scopes = null, + UniverseDomain = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuth + { + Credentials = new() + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }, + ProjectID = "projectId", + Scopes = "string", + UniverseDomain = "universeDomain", + }; + + AgentConfigModelVertexModelConfigObjectAuth copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AgentConfigModelVertexModelConfigObjectAuthCredentialsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }; + + string expectedClientEmail = "client_email"; + string expectedPrivateKey = "private_key"; + string expectedAuthProviderX509CertUrl = "https://example.com"; + string expectedAuthUri = "https://example.com"; + string expectedClientID = "client_id"; + string expectedClientX509CertUrl = "https://example.com"; + string expectedPrivateKeyID = "private_key_id"; + string expectedProjectID = "project_id"; + string expectedTokenUri = "https://example.com"; + ApiEnum expectedType = + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount; + string expectedUniverseDomain = "universe_domain"; + + Assert.Equal(expectedClientEmail, model.ClientEmail); + Assert.Equal(expectedPrivateKey, model.PrivateKey); + Assert.Equal(expectedAuthProviderX509CertUrl, model.AuthProviderX509CertUrl); + Assert.Equal(expectedAuthUri, model.AuthUri); + Assert.Equal(expectedClientID, model.ClientID); + Assert.Equal(expectedClientX509CertUrl, model.ClientX509CertUrl); + Assert.Equal(expectedPrivateKeyID, model.PrivateKeyID); + Assert.Equal(expectedProjectID, model.ProjectID); + Assert.Equal(expectedTokenUri, model.TokenUri); + Assert.Equal(expectedType, model.Type); + Assert.Equal(expectedUniverseDomain, model.UniverseDomain); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedClientEmail = "client_email"; + string expectedPrivateKey = "private_key"; + string expectedAuthProviderX509CertUrl = "https://example.com"; + string expectedAuthUri = "https://example.com"; + string expectedClientID = "client_id"; + string expectedClientX509CertUrl = "https://example.com"; + string expectedPrivateKeyID = "private_key_id"; + string expectedProjectID = "project_id"; + string expectedTokenUri = "https://example.com"; + ApiEnum expectedType = + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount; + string expectedUniverseDomain = "universe_domain"; + + Assert.Equal(expectedClientEmail, deserialized.ClientEmail); + Assert.Equal(expectedPrivateKey, deserialized.PrivateKey); + Assert.Equal(expectedAuthProviderX509CertUrl, deserialized.AuthProviderX509CertUrl); + Assert.Equal(expectedAuthUri, deserialized.AuthUri); + Assert.Equal(expectedClientID, deserialized.ClientID); + Assert.Equal(expectedClientX509CertUrl, deserialized.ClientX509CertUrl); + Assert.Equal(expectedPrivateKeyID, deserialized.PrivateKeyID); + Assert.Equal(expectedProjectID, deserialized.ProjectID); + Assert.Equal(expectedTokenUri, deserialized.TokenUri); + Assert.Equal(expectedType, deserialized.Type); + Assert.Equal(expectedUniverseDomain, deserialized.UniverseDomain); + } + + [Fact] + public void Validation_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + { + ClientEmail = "client_email", + PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + { + ClientEmail = "client_email", + PrivateKey = "private_key", + }; + + Assert.Null(model.AuthProviderX509CertUrl); + Assert.False(model.RawData.ContainsKey("auth_provider_x509_cert_url")); + Assert.Null(model.AuthUri); + Assert.False(model.RawData.ContainsKey("auth_uri")); + Assert.Null(model.ClientID); + Assert.False(model.RawData.ContainsKey("client_id")); + Assert.Null(model.ClientX509CertUrl); + Assert.False(model.RawData.ContainsKey("client_x509_cert_url")); + Assert.Null(model.PrivateKeyID); + Assert.False(model.RawData.ContainsKey("private_key_id")); + Assert.Null(model.ProjectID); + Assert.False(model.RawData.ContainsKey("project_id")); + Assert.Null(model.TokenUri); + Assert.False(model.RawData.ContainsKey("token_uri")); + Assert.Null(model.Type); + Assert.False(model.RawData.ContainsKey("type")); + Assert.Null(model.UniverseDomain); + Assert.False(model.RawData.ContainsKey("universe_domain")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + { + ClientEmail = "client_email", + PrivateKey = "private_key", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + { + ClientEmail = "client_email", + PrivateKey = "private_key", + + // Null should be interpreted as omitted for these properties + AuthProviderX509CertUrl = null, + AuthUri = null, + ClientID = null, + ClientX509CertUrl = null, + PrivateKeyID = null, + ProjectID = null, + TokenUri = null, + Type = null, + UniverseDomain = null, + }; + + Assert.Null(model.AuthProviderX509CertUrl); + Assert.False(model.RawData.ContainsKey("auth_provider_x509_cert_url")); + Assert.Null(model.AuthUri); + Assert.False(model.RawData.ContainsKey("auth_uri")); + Assert.Null(model.ClientID); + Assert.False(model.RawData.ContainsKey("client_id")); + Assert.Null(model.ClientX509CertUrl); + Assert.False(model.RawData.ContainsKey("client_x509_cert_url")); + Assert.Null(model.PrivateKeyID); + Assert.False(model.RawData.ContainsKey("private_key_id")); + Assert.Null(model.ProjectID); + Assert.False(model.RawData.ContainsKey("project_id")); + Assert.Null(model.TokenUri); + Assert.False(model.RawData.ContainsKey("token_uri")); + Assert.Null(model.Type); + Assert.False(model.RawData.ContainsKey("type")); + Assert.Null(model.UniverseDomain); + Assert.False(model.RawData.ContainsKey("universe_domain")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + { + ClientEmail = "client_email", + PrivateKey = "private_key", + + // Null should be interpreted as omitted for these properties + AuthProviderX509CertUrl = null, + AuthUri = null, + ClientID = null, + ClientX509CertUrl = null, + PrivateKeyID = null, + ProjectID = null, + TokenUri = null, + Type = null, + UniverseDomain = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + { + ClientEmail = "client_email", PrivateKey = "private_key", + AuthProviderX509CertUrl = "https://example.com", + AuthUri = "https://example.com", + ClientID = "client_id", + ClientX509CertUrl = "https://example.com", + PrivateKeyID = "private_key_id", + ProjectID = "project_id", + TokenUri = "https://example.com", + Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + UniverseDomain = "universe_domain", + }; + + AgentConfigModelVertexModelConfigObjectAuthCredentials copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AgentConfigModelVertexModelConfigObjectAuthCredentialsTypeTest : TestBase +{ + [Theory] + [InlineData(AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount)] + public void Validation_Works( + AgentConfigModelVertexModelConfigObjectAuthCredentialsType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount)] + public void SerializationRoundtrip_Works( + AgentConfigModelVertexModelConfigObjectAuthCredentialsType rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + +public class AgentConfigModelVertexModelConfigObjectAuthScopesTest : TestBase +{ + [Fact] + public void StringValidationWorks() + { + AgentConfigModelVertexModelConfigObjectAuthScopes value = "string"; + value.Validate(); + } + + [Fact] + public void StringsValidationWorks() + { + AgentConfigModelVertexModelConfigObjectAuthScopes value = new(["string"]); + value.Validate(); + } + + [Fact] + public void StringSerializationRoundtripWorks() + { + AgentConfigModelVertexModelConfigObjectAuthScopes value = "string"; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void StringsSerializationRoundtripWorks() + { + AgentConfigModelVertexModelConfigObjectAuthScopes value = new(["string"]); + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } +} + +public class AgentConfigModelVertexModelConfigObjectProviderOptionsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptions + { + Vertex = new() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + }, + }; + + AgentConfigModelVertexModelConfigObjectProviderOptionsVertex expectedVertex = new() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + Assert.Equal(expectedVertex, model.Vertex); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptions + { + Vertex = new() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptions + { + Vertex = new() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + AgentConfigModelVertexModelConfigObjectProviderOptionsVertex expectedVertex = new() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + Assert.Equal(expectedVertex, deserialized.Vertex); + } + + [Fact] + public void Validation_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptions + { + Vertex = new() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + }, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptions + { + Vertex = new() + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + }, + }; + + AgentConfigModelVertexModelConfigObjectProviderOptions copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AgentConfigModelVertexModelConfigObjectProviderOptionsVertexTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string expectedLocation = "us-central1"; + string expectedProject = "my-gcp-project"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedLocation, model.Location); + Assert.Equal(expectedProject, model.Project); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedLocation = "us-central1"; + string expectedProject = "my-gcp-project"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedLocation, deserialized.Location); + Assert.Equal(expectedProject, deserialized.Project); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + { + Location = "us-central1", + Project = "my-gcp-project", + }; + + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + { + Location = "us-central1", + Project = "my-gcp-project", + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + { + Location = "us-central1", + Project = "my-gcp-project", + + // Null should be interpreted as omitted for these properties + BaseUrl = null, + Headers = null, + }; + + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + { + Location = "us-central1", + Project = "my-gcp-project", + + // Null should be interpreted as omitted for these properties + BaseUrl = null, + Headers = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + { + Location = "us-central1", + Project = "my-gcp-project", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + AgentConfigModelVertexModelConfigObjectProviderOptionsVertex copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AgentConfigModelAzureEntraModelConfigObjectTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + AgentConfigModelAzureEntraModelConfigObjectAuth expectedAuth = new("x"); + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + AgentConfigModelAzureEntraModelConfigObjectProviderOptions expectedProviderOptions = new( + new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedAuth, model.Auth); + Assert.Equal(expectedModelName, model.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, model.Provider)); + Assert.Equal(expectedProviderOptions, model.ProviderOptions); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + AgentConfigModelAzureEntraModelConfigObjectAuth expectedAuth = new("x"); + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + AgentConfigModelAzureEntraModelConfigObjectProviderOptions expectedProviderOptions = new( + new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedAuth, deserialized.Auth); + Assert.Equal(expectedModelName, deserialized.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, deserialized.Provider)); + Assert.Equal(expectedProviderOptions, deserialized.ProviderOptions); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + BaseUrl = null, + Headers = null, + }; + + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + BaseUrl = null, + Headers = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + AgentConfigModelAzureEntraModelConfigObject copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AgentConfigModelAzureEntraModelConfigObjectAuthTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectAuth { Token = "x" }; + + string expectedToken = "x"; + JsonElement expectedType = JsonSerializer.SerializeToElement("azureEntraId"); + + Assert.Equal(expectedToken, model.Token); + Assert.True(JsonElement.DeepEquals(expectedType, model.Type)); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectAuth { Token = "x" }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectAuth { Token = "x" }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedToken = "x"; + JsonElement expectedType = JsonSerializer.SerializeToElement("azureEntraId"); + + Assert.Equal(expectedToken, deserialized.Token); + Assert.True(JsonElement.DeepEquals(expectedType, deserialized.Type)); + } + + [Fact] + public void Validation_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectAuth { Token = "x" }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectAuth { Token = "x" }; + + AgentConfigModelAzureEntraModelConfigObjectAuth copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AgentConfigModelAzureEntraModelConfigObjectProviderOptionsTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure expectedAzure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, model.Azure); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure expectedAzure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, deserialized.Azure); + } + + [Fact] + public void Validation_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + AgentConfigModelAzureEntraModelConfigObjectProviderOptions copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzureTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, model.ApiVersion); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, model.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, model.UseDeploymentBasedUrls); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, deserialized.ApiVersion); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, deserialized.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, deserialized.UseDeploymentBasedUrls); + } + + [Fact] + public void Validation_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure { }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure + { // Null should be interpreted as omitted for these properties - AuthProviderX509CertUrl = null, - AuthUri = null, - ClientID = null, - ClientX509CertUrl = null, - PrivateKeyID = null, - ProjectID = null, - TokenUri = null, - Type = null, - UniverseDomain = null, + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class AgentConfigModelAzureApiKeyModelConfigObjectTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new AgentConfigModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions expectedProviderOptions = new( + new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedModelName, model.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, model.Provider)); + Assert.Equal(expectedProviderOptions, model.ProviderOptions); + Assert.Equal(expectedApiKey, model.ApiKey); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new AgentConfigModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new AgentConfigModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions expectedProviderOptions = new( + new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedModelName, deserialized.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, deserialized.Provider)); + Assert.Equal(expectedProviderOptions, deserialized.ProviderOptions); + Assert.Equal(expectedApiKey, deserialized.ApiKey); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new AgentConfigModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, }; model.Validate(); } [Fact] - public void CopyConstructor_Works() + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() { - var model = new AgentConfigModelVertexModelConfigObjectAuthCredentials + var model = new AgentConfigModelAzureApiKeyModelConfigObject { - ClientEmail = "client_email", - PrivateKey = "private_key", - AuthProviderX509CertUrl = "https://example.com", - AuthUri = "https://example.com", - ClientID = "client_id", - ClientX509CertUrl = "https://example.com", - PrivateKeyID = "private_key_id", - ProjectID = "project_id", - TokenUri = "https://example.com", - Type = AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - UniverseDomain = "universe_domain", + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), }; - AgentConfigModelVertexModelConfigObjectAuthCredentials copied = new(model); - - Assert.Equal(model, copied); - } -} - -public class AgentConfigModelVertexModelConfigObjectAuthCredentialsTypeTest : TestBase -{ - [Theory] - [InlineData(AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount)] - public void Validation_Works( - AgentConfigModelVertexModelConfigObjectAuthCredentialsType rawValue - ) - { - // force implicit conversion because Theory can't do that for us - ApiEnum value = - rawValue; - value.Validate(); + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); } [Fact] - public void InvalidEnumValidationThrows_Works() - { - var value = JsonSerializer.Deserialize< - ApiEnum - >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); - - Assert.NotNull(value); - Assert.Throws(() => value.Validate()); - } - - [Theory] - [InlineData(AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount)] - public void SerializationRoundtrip_Works( - AgentConfigModelVertexModelConfigObjectAuthCredentialsType rawValue - ) + public void OptionalNonNullablePropertiesUnsetValidation_Works() { - // force implicit conversion because Theory can't do that for us - ApiEnum value = - rawValue; - - string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize< - ApiEnum - >(json, ModelBase.SerializerOptions); + var model = new AgentConfigModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; - Assert.Equal(value, deserialized); + model.Validate(); } [Fact] - public void InvalidEnumSerializationRoundtrip_Works() + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() { - var value = JsonSerializer.Deserialize< - ApiEnum - >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); - string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize< - ApiEnum - >(json, ModelBase.SerializerOptions); + var model = new AgentConfigModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), - Assert.Equal(value, deserialized); - } -} + // Null should be interpreted as omitted for these properties + ApiKey = null, + BaseUrl = null, + Headers = null, + }; -public class AgentConfigModelVertexModelConfigObjectAuthScopesTest : TestBase -{ - [Fact] - public void StringValidationWorks() - { - AgentConfigModelVertexModelConfigObjectAuthScopes value = "string"; - value.Validate(); + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); } [Fact] - public void StringsValidationWorks() + public void OptionalNonNullablePropertiesSetToNullValidation_Works() { - AgentConfigModelVertexModelConfigObjectAuthScopes value = new(["string"]); - value.Validate(); - } + var model = new AgentConfigModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), - [Fact] - public void StringSerializationRoundtripWorks() - { - AgentConfigModelVertexModelConfigObjectAuthScopes value = "string"; - string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = - JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); + // Null should be interpreted as omitted for these properties + ApiKey = null, + BaseUrl = null, + Headers = null, + }; - Assert.Equal(value, deserialized); + model.Validate(); } [Fact] - public void StringsSerializationRoundtripWorks() + public void CopyConstructor_Works() { - AgentConfigModelVertexModelConfigObjectAuthScopes value = new(["string"]); - string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = - JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); + var model = new AgentConfigModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; - Assert.Equal(value, deserialized); + AgentConfigModelAzureApiKeyModelConfigObject copied = new(model); + + Assert.Equal(model, copied); } } -public class AgentConfigModelVertexModelConfigObjectProviderOptionsTest : TestBase +public class AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsTest : TestBase { [Fact] public void FieldRoundtrip_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptions + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions { - Vertex = new() + Azure = new() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }, }; - AgentConfigModelVertexModelConfigObjectProviderOptionsVertex expectedVertex = new() + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure expectedAzure = new() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; - Assert.Equal(expectedVertex, model.Vertex); + Assert.Equal(expectedAzure, model.Azure); } [Fact] public void SerializationRoundtrip_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptions + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions { - Vertex = new() + Azure = new() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }, }; string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); var deserialized = - JsonSerializer.Deserialize( + JsonSerializer.Deserialize( json, ModelBase.SerializerOptions ); @@ -5088,47 +7895,50 @@ public void SerializationRoundtrip_Works() [Fact] public void FieldRoundtripThroughSerialization_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptions + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions { - Vertex = new() + Azure = new() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }, }; string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); var deserialized = - JsonSerializer.Deserialize( + JsonSerializer.Deserialize( element, ModelBase.SerializerOptions ); Assert.NotNull(deserialized); - AgentConfigModelVertexModelConfigObjectProviderOptionsVertex expectedVertex = new() + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure expectedAzure = new() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; - Assert.Equal(expectedVertex, deserialized.Vertex); + Assert.Equal(expectedAzure, deserialized.Azure); } [Fact] public void Validation_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptions + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions { - Vertex = new() + Azure = new() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }, }; @@ -5138,43 +7948,45 @@ public void Validation_Works() [Fact] public void CopyConstructor_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptions + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions { - Vertex = new() + Azure = new() { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }, }; - AgentConfigModelVertexModelConfigObjectProviderOptions copied = new(model); + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions copied = new(model); Assert.Equal(model, copied); } } -public class AgentConfigModelVertexModelConfigObjectProviderOptionsVertexTest : TestBase +public class AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzureTest : TestBase { [Fact] public void FieldRoundtrip_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; - string expectedLocation = "us-central1"; - string expectedProject = "my-gcp-project"; + string expectedApiVersion = "2024-10-01-preview"; string expectedBaseUrl = "https://example.com"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; - Assert.Equal(expectedLocation, model.Location); - Assert.Equal(expectedProject, model.Project); + Assert.Equal(expectedApiVersion, model.ApiVersion); Assert.Equal(expectedBaseUrl, model.BaseUrl); Assert.NotNull(model.Headers); Assert.Equal(expectedHeaders.Count, model.Headers.Count); @@ -5184,22 +7996,25 @@ public void FieldRoundtrip_Works() Assert.Equal(value, model.Headers[item.Key]); } + Assert.Equal(expectedResourceName, model.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, model.UseDeploymentBasedUrls); } [Fact] public void SerializationRoundtrip_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); var deserialized = - JsonSerializer.Deserialize( + JsonSerializer.Deserialize( json, ModelBase.SerializerOptions ); @@ -5210,29 +8025,30 @@ public void SerializationRoundtrip_Works() [Fact] public void FieldRoundtripThroughSerialization_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); var deserialized = - JsonSerializer.Deserialize( + JsonSerializer.Deserialize( element, ModelBase.SerializerOptions ); Assert.NotNull(deserialized); - string expectedLocation = "us-central1"; - string expectedProject = "my-gcp-project"; + string expectedApiVersion = "2024-10-01-preview"; string expectedBaseUrl = "https://example.com"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; - Assert.Equal(expectedLocation, deserialized.Location); - Assert.Equal(expectedProject, deserialized.Project); + Assert.Equal(expectedApiVersion, deserialized.ApiVersion); Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); Assert.NotNull(deserialized.Headers); Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); @@ -5242,17 +8058,20 @@ public void FieldRoundtripThroughSerialization_Works() Assert.Equal(value, deserialized.Headers[item.Key]); } + Assert.Equal(expectedResourceName, deserialized.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, deserialized.UseDeploymentBasedUrls); } [Fact] public void Validation_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; model.Validate(); @@ -5261,26 +8080,24 @@ public void Validation_Works() [Fact] public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex - { - Location = "us-central1", - Project = "my-gcp-project", - }; + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure { }; + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); Assert.Null(model.BaseUrl); Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); } [Fact] public void OptionalNonNullablePropertiesUnsetValidation_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex - { - Location = "us-central1", - Project = "my-gcp-project", - }; + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure { }; model.Validate(); } @@ -5288,33 +8105,39 @@ public void OptionalNonNullablePropertiesUnsetValidation_Works() [Fact] public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure { - Location = "us-central1", - Project = "my-gcp-project", - // Null should be interpreted as omitted for these properties + ApiVersion = null, BaseUrl = null, Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, }; + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); Assert.Null(model.BaseUrl); Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); } [Fact] public void OptionalNonNullablePropertiesSetToNullValidation_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure { - Location = "us-central1", - Project = "my-gcp-project", - // Null should be interpreted as omitted for these properties + ApiVersion = null, BaseUrl = null, Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, }; model.Validate(); @@ -5323,15 +8146,16 @@ public void OptionalNonNullablePropertiesSetToNullValidation_Works() [Fact] public void CopyConstructor_Works() { - var model = new AgentConfigModelVertexModelConfigObjectProviderOptionsVertex + var model = new AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure { - Location = "us-central1", - Project = "my-gcp-project", + ApiVersion = "2024-10-01-preview", BaseUrl = "https://example.com", Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, }; - AgentConfigModelVertexModelConfigObjectProviderOptionsVertex copied = new(model); + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure copied = new(model); Assert.Equal(model, copied); } diff --git a/src/Stagehand.Tests/Models/Sessions/SessionExtractParamsTest.cs b/src/Stagehand.Tests/Models/Sessions/SessionExtractParamsTest.cs index 3c3947f..1188751 100644 --- a/src/Stagehand.Tests/Models/Sessions/SessionExtractParamsTest.cs +++ b/src/Stagehand.Tests/Models/Sessions/SessionExtractParamsTest.cs @@ -909,6 +909,54 @@ public void VertexModelConfigObjectValidationWorks() value.Validate(); } + [Fact] + public void AzureEntraModelConfigObjectValidationWorks() + { + SessionExtractParamsOptionsModel value = + new SessionExtractParamsOptionsModelAzureEntraModelConfigObject() + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + value.Validate(); + } + + [Fact] + public void AzureApiKeyModelConfigObjectValidationWorks() + { + SessionExtractParamsOptionsModel value = + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + value.Validate(); + } + [Fact] public void GenericModelConfigObjectValidationWorks() { @@ -981,6 +1029,66 @@ public void VertexModelConfigObjectSerializationRoundtripWorks() Assert.Equal(value, deserialized); } + [Fact] + public void AzureEntraModelConfigObjectSerializationRoundtripWorks() + { + SessionExtractParamsOptionsModel value = + new SessionExtractParamsOptionsModelAzureEntraModelConfigObject() + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AzureApiKeyModelConfigObjectSerializationRoundtripWorks() + { + SessionExtractParamsOptionsModel value = + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + [Fact] public void GenericModelConfigObjectSerializationRoundtripWorks() { @@ -2588,6 +2696,1371 @@ public void CopyConstructor_Works() } } +public class SessionExtractParamsOptionsModelAzureEntraModelConfigObjectTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth expectedAuth = new("x"); + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions expectedProviderOptions = + new( + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedAuth, model.Auth); + Assert.Equal(expectedModelName, model.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, model.Provider)); + Assert.Equal(expectedProviderOptions, model.ProviderOptions); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth expectedAuth = new("x"); + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions expectedProviderOptions = + new( + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedAuth, deserialized.Auth); + Assert.Equal(expectedModelName, deserialized.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, deserialized.Provider)); + Assert.Equal(expectedProviderOptions, deserialized.ProviderOptions); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + BaseUrl = null, + Headers = null, + }; + + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + BaseUrl = null, + Headers = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + SessionExtractParamsOptionsModelAzureEntraModelConfigObject copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuthTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth + { + Token = "x", + }; + + string expectedToken = "x"; + JsonElement expectedType = JsonSerializer.SerializeToElement("azureEntraId"); + + Assert.Equal(expectedToken, model.Token); + Assert.True(JsonElement.DeepEquals(expectedType, model.Type)); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth + { + Token = "x", + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth + { + Token = "x", + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedToken = "x"; + JsonElement expectedType = JsonSerializer.SerializeToElement("azureEntraId"); + + Assert.Equal(expectedToken, deserialized.Token); + Assert.True(JsonElement.DeepEquals(expectedType, deserialized.Type)); + } + + [Fact] + public void Validation_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth + { + Token = "x", + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth + { + Token = "x", + }; + + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure expectedAzure = + new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, model.Azure); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure expectedAzure = + new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, deserialized.Azure); + } + + [Fact] + public void Validation_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions copied = new( + model + ); + + Assert.Equal(model, copied); + } +} + +public class SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzureTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, model.ApiVersion); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, model.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, model.UseDeploymentBasedUrls); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, deserialized.ApiVersion); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, deserialized.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, deserialized.UseDeploymentBasedUrls); + } + + [Fact] + public void Validation_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure { }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure copied = + new(model); + + Assert.Equal(model, copied); + } +} + +public class SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions expectedProviderOptions = + new( + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedModelName, model.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, model.Provider)); + Assert.Equal(expectedProviderOptions, model.ProviderOptions); + Assert.Equal(expectedApiKey, model.ApiKey); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions expectedProviderOptions = + new( + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedModelName, deserialized.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, deserialized.Provider)); + Assert.Equal(expectedProviderOptions, deserialized.ProviderOptions); + Assert.Equal(expectedApiKey, deserialized.ApiKey); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + ApiKey = null, + BaseUrl = null, + Headers = null, + }; + + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + ApiKey = null, + BaseUrl = null, + Headers = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure expectedAzure = + new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, model.Azure); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure expectedAzure = + new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, deserialized.Azure); + } + + [Fact] + public void Validation_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions copied = new( + model + ); + + Assert.Equal(model, copied); + } +} + +public class SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzureTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, model.ApiVersion); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, model.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, model.UseDeploymentBasedUrls); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, deserialized.ApiVersion); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, deserialized.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, deserialized.UseDeploymentBasedUrls); + } + + [Fact] + public void Validation_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = + new SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure copied = + new(model); + + Assert.Equal(model, copied); + } +} + public class SessionExtractParamsOptionsModelGenericModelConfigObjectTest : TestBase { [Fact] diff --git a/src/Stagehand.Tests/Models/Sessions/SessionObserveParamsTest.cs b/src/Stagehand.Tests/Models/Sessions/SessionObserveParamsTest.cs index b5a6a9a..81a2142 100644 --- a/src/Stagehand.Tests/Models/Sessions/SessionObserveParamsTest.cs +++ b/src/Stagehand.Tests/Models/Sessions/SessionObserveParamsTest.cs @@ -1022,6 +1022,54 @@ public void VertexModelConfigObjectValidationWorks() value.Validate(); } + [Fact] + public void AzureEntraModelConfigObjectValidationWorks() + { + SessionObserveParamsOptionsModel value = + new SessionObserveParamsOptionsModelAzureEntraModelConfigObject() + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + value.Validate(); + } + + [Fact] + public void AzureApiKeyModelConfigObjectValidationWorks() + { + SessionObserveParamsOptionsModel value = + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + value.Validate(); + } + [Fact] public void GenericModelConfigObjectValidationWorks() { @@ -1094,6 +1142,66 @@ public void VertexModelConfigObjectSerializationRoundtripWorks() Assert.Equal(value, deserialized); } + [Fact] + public void AzureEntraModelConfigObjectSerializationRoundtripWorks() + { + SessionObserveParamsOptionsModel value = + new SessionObserveParamsOptionsModelAzureEntraModelConfigObject() + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void AzureApiKeyModelConfigObjectSerializationRoundtripWorks() + { + SessionObserveParamsOptionsModel value = + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject() + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + + Assert.Equal(value, deserialized); + } + [Fact] public void GenericModelConfigObjectSerializationRoundtripWorks() { @@ -2701,6 +2809,1371 @@ public void CopyConstructor_Works() } } +public class SessionObserveParamsOptionsModelAzureEntraModelConfigObjectTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth expectedAuth = new("x"); + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions expectedProviderOptions = + new( + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedAuth, model.Auth); + Assert.Equal(expectedModelName, model.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, model.Provider)); + Assert.Equal(expectedProviderOptions, model.ProviderOptions); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth expectedAuth = new("x"); + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions expectedProviderOptions = + new( + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedAuth, deserialized.Auth); + Assert.Equal(expectedModelName, deserialized.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, deserialized.Provider)); + Assert.Equal(expectedProviderOptions, deserialized.ProviderOptions); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + BaseUrl = null, + Headers = null, + }; + + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + BaseUrl = null, + Headers = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObject + { + Auth = new("x"), + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + SessionObserveParamsOptionsModelAzureEntraModelConfigObject copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuthTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth + { + Token = "x", + }; + + string expectedToken = "x"; + JsonElement expectedType = JsonSerializer.SerializeToElement("azureEntraId"); + + Assert.Equal(expectedToken, model.Token); + Assert.True(JsonElement.DeepEquals(expectedType, model.Type)); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth + { + Token = "x", + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth + { + Token = "x", + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedToken = "x"; + JsonElement expectedType = JsonSerializer.SerializeToElement("azureEntraId"); + + Assert.Equal(expectedToken, deserialized.Token); + Assert.True(JsonElement.DeepEquals(expectedType, deserialized.Type)); + } + + [Fact] + public void Validation_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth + { + Token = "x", + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth + { + Token = "x", + }; + + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure expectedAzure = + new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, model.Azure); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure expectedAzure = + new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, deserialized.Azure); + } + + [Fact] + public void Validation_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions copied = new( + model + ); + + Assert.Equal(model, copied); + } +} + +public class SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzureTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, model.ApiVersion); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, model.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, model.UseDeploymentBasedUrls); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, deserialized.ApiVersion); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, deserialized.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, deserialized.UseDeploymentBasedUrls); + } + + [Fact] + public void Validation_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure { }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure copied = + new(model); + + Assert.Equal(model, copied); + } +} + +public class SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectTest : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions expectedProviderOptions = + new( + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedModelName, model.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, model.Provider)); + Assert.Equal(expectedProviderOptions, model.ProviderOptions); + Assert.Equal(expectedApiKey, model.ApiKey); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedModelName = "openai/gpt-5.4-mini"; + JsonElement expectedProvider = JsonSerializer.SerializeToElement("azure"); + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions expectedProviderOptions = + new( + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ); + string expectedApiKey = "sk-some-openai-api-key"; + string expectedBaseUrl = "https://api.openai.com/v1"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + + Assert.Equal(expectedModelName, deserialized.ModelName); + Assert.True(JsonElement.DeepEquals(expectedProvider, deserialized.Provider)); + Assert.Equal(expectedProviderOptions, deserialized.ProviderOptions); + Assert.Equal(expectedApiKey, deserialized.ApiKey); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + } + + [Fact] + public void Validation_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + ApiKey = null, + BaseUrl = null, + Headers = null, + }; + + Assert.Null(model.ApiKey); + Assert.False(model.RawData.ContainsKey("apiKey")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + + // Null should be interpreted as omitted for these properties + ApiKey = null, + BaseUrl = null, + Headers = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject + { + ModelName = "openai/gpt-5.4-mini", + ProviderOptions = new( + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + } + ), + ApiKey = "sk-some-openai-api-key", + BaseUrl = "https://api.openai.com/v1", + Headers = new Dictionary() { { "foo", "string" } }, + }; + + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject copied = new(model); + + Assert.Equal(model, copied); + } +} + +public class SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure expectedAzure = + new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, model.Azure); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure expectedAzure = + new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + Assert.Equal(expectedAzure, deserialized.Azure); + } + + [Fact] + public void Validation_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + { + Azure = new() + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }, + }; + + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions copied = new( + model + ); + + Assert.Equal(model, copied); + } +} + +public class SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzureTest + : TestBase +{ + [Fact] + public void FieldRoundtrip_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, model.ApiVersion); + Assert.Equal(expectedBaseUrl, model.BaseUrl); + Assert.NotNull(model.Headers); + Assert.Equal(expectedHeaders.Count, model.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(model.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, model.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, model.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, model.UseDeploymentBasedUrls); + } + + [Fact] + public void SerializationRoundtrip_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + json, + ModelBase.SerializerOptions + ); + + Assert.Equal(model, deserialized); + } + + [Fact] + public void FieldRoundtripThroughSerialization_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); + var deserialized = + JsonSerializer.Deserialize( + element, + ModelBase.SerializerOptions + ); + Assert.NotNull(deserialized); + + string expectedApiVersion = "2024-10-01-preview"; + string expectedBaseUrl = "https://example.com"; + Dictionary expectedHeaders = new() { { "foo", "string" } }; + string expectedResourceName = "my-azure-openai-resource"; + bool expectedUseDeploymentBasedUrls = true; + + Assert.Equal(expectedApiVersion, deserialized.ApiVersion); + Assert.Equal(expectedBaseUrl, deserialized.BaseUrl); + Assert.NotNull(deserialized.Headers); + Assert.Equal(expectedHeaders.Count, deserialized.Headers.Count); + foreach (var item in expectedHeaders) + { + Assert.True(deserialized.Headers.TryGetValue(item.Key, out var value)); + + Assert.Equal(value, deserialized.Headers[item.Key]); + } + Assert.Equal(expectedResourceName, deserialized.ResourceName); + Assert.Equal(expectedUseDeploymentBasedUrls, deserialized.UseDeploymentBasedUrls); + } + + [Fact] + public void Validation_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesUnsetValidation_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { }; + + model.Validate(); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + Assert.Null(model.ApiVersion); + Assert.False(model.RawData.ContainsKey("apiVersion")); + Assert.Null(model.BaseUrl); + Assert.False(model.RawData.ContainsKey("baseURL")); + Assert.Null(model.Headers); + Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.ResourceName); + Assert.False(model.RawData.ContainsKey("resourceName")); + Assert.Null(model.UseDeploymentBasedUrls); + Assert.False(model.RawData.ContainsKey("useDeploymentBasedUrls")); + } + + [Fact] + public void OptionalNonNullablePropertiesSetToNullValidation_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + // Null should be interpreted as omitted for these properties + ApiVersion = null, + BaseUrl = null, + Headers = null, + ResourceName = null, + UseDeploymentBasedUrls = null, + }; + + model.Validate(); + } + + [Fact] + public void CopyConstructor_Works() + { + var model = + new SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + { + ApiVersion = "2024-10-01-preview", + BaseUrl = "https://example.com", + Headers = new Dictionary() { { "foo", "string" } }, + ResourceName = "my-azure-openai-resource", + UseDeploymentBasedUrls = true, + }; + + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure copied = + new(model); + + Assert.Equal(model, copied); + } +} + public class SessionObserveParamsOptionsModelGenericModelConfigObjectTest : TestBase { [Fact] diff --git a/src/Stagehand/Models/Sessions/ModelConfig.cs b/src/Stagehand/Models/Sessions/ModelConfig.cs index da083aa..70ec95f 100644 --- a/src/Stagehand/Models/Sessions/ModelConfig.cs +++ b/src/Stagehand/Models/Sessions/ModelConfig.cs @@ -34,6 +34,8 @@ public string ModelName { return Match( vertexModelConfigObject: (x) => x.ModelName, + azureEntraModelConfigObject: (x) => x.ModelName, + azureApiKeyModelConfigObject: (x) => x.ModelName, genericModelConfigObject: (x) => x.ModelName ); } @@ -45,6 +47,8 @@ public string? ApiKey { return Match( vertexModelConfigObject: (x) => x.ApiKey, + azureEntraModelConfigObject: (_) => null, + azureApiKeyModelConfigObject: (x) => x.ApiKey, genericModelConfigObject: (x) => x.ApiKey ); } @@ -56,6 +60,8 @@ public string? BaseUrl { return Match( vertexModelConfigObject: (x) => x.BaseUrl, + azureEntraModelConfigObject: (x) => x.BaseUrl, + azureApiKeyModelConfigObject: (x) => x.BaseUrl, genericModelConfigObject: (x) => x.BaseUrl ); } @@ -67,6 +73,18 @@ public ModelConfig(ModelConfigVertexModelConfigObject value, JsonElement? elemen this._element = element; } + public ModelConfig(ModelConfigAzureEntraModelConfigObject value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public ModelConfig(ModelConfigAzureApiKeyModelConfigObject value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + public ModelConfig(ModelConfigGenericModelConfigObject value, JsonElement? element = null) { this.Value = value; @@ -101,6 +119,52 @@ public bool TryPickVertexModelConfigObject( return value != null; } + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAzureEntraModelConfigObject(out var value)) { + /// // `value` is of type `ModelConfigAzureEntraModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAzureEntraModelConfigObject( + [NotNullWhen(true)] out ModelConfigAzureEntraModelConfigObject? value + ) + { + value = this.Value as ModelConfigAzureEntraModelConfigObject; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAzureApiKeyModelConfigObject(out var value)) { + /// // `value` is of type `ModelConfigAzureApiKeyModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAzureApiKeyModelConfigObject( + [NotNullWhen(true)] out ModelConfigAzureApiKeyModelConfigObject? value + ) + { + value = this.Value as ModelConfigAzureApiKeyModelConfigObject; + return value != null; + } + /// /// Returns true and sets the out parameter if the instance was constructed with a variant of /// type . @@ -139,6 +203,8 @@ public bool TryPickGenericModelConfigObject( /// /// instance.Switch( /// (ModelConfigVertexModelConfigObject value) => {...}, + /// (ModelConfigAzureEntraModelConfigObject value) => {...}, + /// (ModelConfigAzureApiKeyModelConfigObject value) => {...}, /// (ModelConfigGenericModelConfigObject value) => {...} /// ); /// @@ -146,6 +212,8 @@ public bool TryPickGenericModelConfigObject( /// public void Switch( System::Action vertexModelConfigObject, + System::Action azureEntraModelConfigObject, + System::Action azureApiKeyModelConfigObject, System::Action genericModelConfigObject ) { @@ -154,6 +222,12 @@ public void Switch( case ModelConfigVertexModelConfigObject value: vertexModelConfigObject(value); break; + case ModelConfigAzureEntraModelConfigObject value: + azureEntraModelConfigObject(value); + break; + case ModelConfigAzureApiKeyModelConfigObject value: + azureApiKeyModelConfigObject(value); + break; case ModelConfigGenericModelConfigObject value: genericModelConfigObject(value); break; @@ -180,6 +254,8 @@ public void Switch( /// /// var result = instance.Match( /// (ModelConfigVertexModelConfigObject value) => {...}, + /// (ModelConfigAzureEntraModelConfigObject value) => {...}, + /// (ModelConfigAzureApiKeyModelConfigObject value) => {...}, /// (ModelConfigGenericModelConfigObject value) => {...} /// ); /// @@ -187,12 +263,16 @@ public void Switch( /// public T Match( System::Func vertexModelConfigObject, + System::Func azureEntraModelConfigObject, + System::Func azureApiKeyModelConfigObject, System::Func genericModelConfigObject ) { return this.Value switch { ModelConfigVertexModelConfigObject value => vertexModelConfigObject(value), + ModelConfigAzureEntraModelConfigObject value => azureEntraModelConfigObject(value), + ModelConfigAzureApiKeyModelConfigObject value => azureApiKeyModelConfigObject(value), ModelConfigGenericModelConfigObject value => genericModelConfigObject(value), _ => throw new StagehandInvalidDataException( "Data did not match any variant of ModelConfig" @@ -203,6 +283,12 @@ public T Match( public static implicit operator ModelConfig(ModelConfigVertexModelConfigObject value) => new(value); + public static implicit operator ModelConfig(ModelConfigAzureEntraModelConfigObject value) => + new(value); + + public static implicit operator ModelConfig(ModelConfigAzureApiKeyModelConfigObject value) => + new(value); + public static implicit operator ModelConfig(ModelConfigGenericModelConfigObject value) => new(value); @@ -226,6 +312,8 @@ public override void Validate() } this.Switch( (vertexModelConfigObject) => vertexModelConfigObject.Validate(), + (azureEntraModelConfigObject) => azureEntraModelConfigObject.Validate(), + (azureApiKeyModelConfigObject) => azureApiKeyModelConfigObject.Validate(), (genericModelConfigObject) => genericModelConfigObject.Validate() ); } @@ -251,7 +339,9 @@ int VariantIndex() return this.Value switch { ModelConfigVertexModelConfigObject _ => 0, - ModelConfigGenericModelConfigObject _ => 1, + ModelConfigAzureEntraModelConfigObject _ => 1, + ModelConfigAzureApiKeyModelConfigObject _ => 2, + ModelConfigGenericModelConfigObject _ => 3, _ => -1, }; } @@ -283,6 +373,40 @@ JsonSerializerOptions options // ignore } + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + try { var deserialized = JsonSerializer.Deserialize( @@ -1458,6 +1582,972 @@ IReadOnlyDictionary rawData ) => ModelConfigVertexModelConfigObjectProviderOptionsVertex.FromRawUnchecked(rawData); } +[JsonConverter( + typeof(JsonModelConverter< + ModelConfigAzureEntraModelConfigObject, + ModelConfigAzureEntraModelConfigObjectFromRaw + >) +)] +public sealed record class ModelConfigAzureEntraModelConfigObject : JsonModel +{ + /// + /// Azure provider authentication configuration + /// + public required ModelConfigAzureEntraModelConfigObjectAuth Auth + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "auth" + ); + } + init { this._rawData.Set("auth", value); } + } + + /// + /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + /// + public required string ModelName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("modelName"); + } + init { this._rawData.Set("modelName", value); } + } + + /// + /// Azure OpenAI model provider + /// + public JsonElement Provider + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("provider"); + } + init { this._rawData.Set("provider", value); } + } + + /// + /// Azure provider-specific model configuration + /// + public required ModelConfigAzureEntraModelConfigObjectProviderOptions ProviderOptions + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "providerOptions" + ); + } + init { this._rawData.Set("providerOptions", value); } + } + + /// + /// Base URL for the model provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the model provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + public override void Validate() + { + this.Auth.Validate(); + _ = this.ModelName; + if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("azure"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + this.ProviderOptions.Validate(); + _ = this.BaseUrl; + _ = this.Headers; + } + + public ModelConfigAzureEntraModelConfigObject() + { + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ModelConfigAzureEntraModelConfigObject( + ModelConfigAzureEntraModelConfigObject modelConfigAzureEntraModelConfigObject + ) + : base(modelConfigAzureEntraModelConfigObject) { } +#pragma warning restore CS8618 + + public ModelConfigAzureEntraModelConfigObject(IReadOnlyDictionary rawData) + { + this._rawData = new(rawData); + + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ModelConfigAzureEntraModelConfigObject(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ModelConfigAzureEntraModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ModelConfigAzureEntraModelConfigObjectFromRaw + : IFromRawJson +{ + /// + public ModelConfigAzureEntraModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ModelConfigAzureEntraModelConfigObject.FromRawUnchecked(rawData); +} + +/// +/// Azure provider authentication configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + ModelConfigAzureEntraModelConfigObjectAuth, + ModelConfigAzureEntraModelConfigObjectAuthFromRaw + >) +)] +public sealed record class ModelConfigAzureEntraModelConfigObjectAuth : JsonModel +{ + /// + /// Microsoft Entra ID bearer token for Azure OpenAI + /// + public required string Token + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("token"); + } + init { this._rawData.Set("token", value); } + } + + /// + /// Use a Microsoft Entra ID bearer token for authentication + /// + public JsonElement Type + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("type"); + } + init { this._rawData.Set("type", value); } + } + + /// + public override void Validate() + { + _ = this.Token; + if (!JsonElement.DeepEquals(this.Type, JsonSerializer.SerializeToElement("azureEntraId"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + } + + public ModelConfigAzureEntraModelConfigObjectAuth() + { + this.Type = JsonSerializer.SerializeToElement("azureEntraId"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ModelConfigAzureEntraModelConfigObjectAuth( + ModelConfigAzureEntraModelConfigObjectAuth modelConfigAzureEntraModelConfigObjectAuth + ) + : base(modelConfigAzureEntraModelConfigObjectAuth) { } +#pragma warning restore CS8618 + + public ModelConfigAzureEntraModelConfigObjectAuth( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + + this.Type = JsonSerializer.SerializeToElement("azureEntraId"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ModelConfigAzureEntraModelConfigObjectAuth(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ModelConfigAzureEntraModelConfigObjectAuth FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ModelConfigAzureEntraModelConfigObjectAuth(string token) + : this() + { + this.Token = token; + } +} + +class ModelConfigAzureEntraModelConfigObjectAuthFromRaw + : IFromRawJson +{ + /// + public ModelConfigAzureEntraModelConfigObjectAuth FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ModelConfigAzureEntraModelConfigObjectAuth.FromRawUnchecked(rawData); +} + +/// +/// Azure provider-specific model configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + ModelConfigAzureEntraModelConfigObjectProviderOptions, + ModelConfigAzureEntraModelConfigObjectProviderOptionsFromRaw + >) +)] +public sealed record class ModelConfigAzureEntraModelConfigObjectProviderOptions : JsonModel +{ + /// + /// Azure OpenAI provider-specific settings + /// + public required ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure Azure + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "azure" + ); + } + init { this._rawData.Set("azure", value); } + } + + /// + public override void Validate() + { + this.Azure.Validate(); + } + + public ModelConfigAzureEntraModelConfigObjectProviderOptions() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ModelConfigAzureEntraModelConfigObjectProviderOptions( + ModelConfigAzureEntraModelConfigObjectProviderOptions modelConfigAzureEntraModelConfigObjectProviderOptions + ) + : base(modelConfigAzureEntraModelConfigObjectProviderOptions) { } +#pragma warning restore CS8618 + + public ModelConfigAzureEntraModelConfigObjectProviderOptions( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ModelConfigAzureEntraModelConfigObjectProviderOptions( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ModelConfigAzureEntraModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ModelConfigAzureEntraModelConfigObjectProviderOptions( + ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure azure + ) + : this() + { + this.Azure = azure; + } +} + +class ModelConfigAzureEntraModelConfigObjectProviderOptionsFromRaw + : IFromRawJson +{ + /// + public ModelConfigAzureEntraModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ModelConfigAzureEntraModelConfigObjectProviderOptions.FromRawUnchecked(rawData); +} + +/// +/// Azure OpenAI provider-specific settings +/// +[JsonConverter( + typeof(JsonModelConverter< + ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure, + ModelConfigAzureEntraModelConfigObjectProviderOptionsAzureFromRaw + >) +)] +public sealed record class ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure : JsonModel +{ + /// + /// Azure OpenAI API version + /// + public string? ApiVersion + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiVersion"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiVersion", value); + } + } + + /// + /// Base URL for the Azure OpenAI provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the Azure OpenAI provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + /// Azure OpenAI resource name + /// + public string? ResourceName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("resourceName"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("resourceName", value); + } + } + + /// + /// Whether to use deployment-based Azure OpenAI URLs + /// + public bool? UseDeploymentBasedUrls + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableStruct("useDeploymentBasedUrls"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("useDeploymentBasedUrls", value); + } + } + + /// + public override void Validate() + { + _ = this.ApiVersion; + _ = this.BaseUrl; + _ = this.Headers; + _ = this.ResourceName; + _ = this.UseDeploymentBasedUrls; + } + + public ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure( + ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure modelConfigAzureEntraModelConfigObjectProviderOptionsAzure + ) + : base(modelConfigAzureEntraModelConfigObjectProviderOptionsAzure) { } +#pragma warning restore CS8618 + + public ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ModelConfigAzureEntraModelConfigObjectProviderOptionsAzureFromRaw + : IFromRawJson +{ + /// + public ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ModelConfigAzureEntraModelConfigObjectProviderOptionsAzure.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + ModelConfigAzureApiKeyModelConfigObject, + ModelConfigAzureApiKeyModelConfigObjectFromRaw + >) +)] +public sealed record class ModelConfigAzureApiKeyModelConfigObject : JsonModel +{ + /// + /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + /// + public required string ModelName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("modelName"); + } + init { this._rawData.Set("modelName", value); } + } + + /// + /// Azure OpenAI model provider + /// + public JsonElement Provider + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("provider"); + } + init { this._rawData.Set("provider", value); } + } + + /// + /// Azure provider-specific model configuration + /// + public required ModelConfigAzureApiKeyModelConfigObjectProviderOptions ProviderOptions + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "providerOptions" + ); + } + init { this._rawData.Set("providerOptions", value); } + } + + /// + /// API key for the model provider + /// + public string? ApiKey + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiKey"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiKey", value); + } + } + + /// + /// Base URL for the model provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the model provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + public override void Validate() + { + _ = this.ModelName; + if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("azure"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + this.ProviderOptions.Validate(); + _ = this.ApiKey; + _ = this.BaseUrl; + _ = this.Headers; + } + + public ModelConfigAzureApiKeyModelConfigObject() + { + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ModelConfigAzureApiKeyModelConfigObject( + ModelConfigAzureApiKeyModelConfigObject modelConfigAzureApiKeyModelConfigObject + ) + : base(modelConfigAzureApiKeyModelConfigObject) { } +#pragma warning restore CS8618 + + public ModelConfigAzureApiKeyModelConfigObject(IReadOnlyDictionary rawData) + { + this._rawData = new(rawData); + + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ModelConfigAzureApiKeyModelConfigObject(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ModelConfigAzureApiKeyModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ModelConfigAzureApiKeyModelConfigObjectFromRaw + : IFromRawJson +{ + /// + public ModelConfigAzureApiKeyModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ModelConfigAzureApiKeyModelConfigObject.FromRawUnchecked(rawData); +} + +/// +/// Azure provider-specific model configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + ModelConfigAzureApiKeyModelConfigObjectProviderOptions, + ModelConfigAzureApiKeyModelConfigObjectProviderOptionsFromRaw + >) +)] +public sealed record class ModelConfigAzureApiKeyModelConfigObjectProviderOptions : JsonModel +{ + /// + /// Azure OpenAI provider-specific settings + /// + public required ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure Azure + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "azure" + ); + } + init { this._rawData.Set("azure", value); } + } + + /// + public override void Validate() + { + this.Azure.Validate(); + } + + public ModelConfigAzureApiKeyModelConfigObjectProviderOptions() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ModelConfigAzureApiKeyModelConfigObjectProviderOptions( + ModelConfigAzureApiKeyModelConfigObjectProviderOptions modelConfigAzureApiKeyModelConfigObjectProviderOptions + ) + : base(modelConfigAzureApiKeyModelConfigObjectProviderOptions) { } +#pragma warning restore CS8618 + + public ModelConfigAzureApiKeyModelConfigObjectProviderOptions( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ModelConfigAzureApiKeyModelConfigObjectProviderOptions( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ModelConfigAzureApiKeyModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ModelConfigAzureApiKeyModelConfigObjectProviderOptions( + ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure azure + ) + : this() + { + this.Azure = azure; + } +} + +class ModelConfigAzureApiKeyModelConfigObjectProviderOptionsFromRaw + : IFromRawJson +{ + /// + public ModelConfigAzureApiKeyModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ModelConfigAzureApiKeyModelConfigObjectProviderOptions.FromRawUnchecked(rawData); +} + +/// +/// Azure OpenAI provider-specific settings +/// +[JsonConverter( + typeof(JsonModelConverter< + ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure, + ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzureFromRaw + >) +)] +public sealed record class ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure : JsonModel +{ + /// + /// Azure OpenAI API version + /// + public string? ApiVersion + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiVersion"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiVersion", value); + } + } + + /// + /// Base URL for the Azure OpenAI provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the Azure OpenAI provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + /// Azure OpenAI resource name + /// + public string? ResourceName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("resourceName"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("resourceName", value); + } + } + + /// + /// Whether to use deployment-based Azure OpenAI URLs + /// + public bool? UseDeploymentBasedUrls + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableStruct("useDeploymentBasedUrls"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("useDeploymentBasedUrls", value); + } + } + + /// + public override void Validate() + { + _ = this.ApiVersion; + _ = this.BaseUrl; + _ = this.Headers; + _ = this.ResourceName; + _ = this.UseDeploymentBasedUrls; + } + + public ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure( + ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure modelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure + ) + : base(modelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure) { } +#pragma warning restore CS8618 + + public ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzureFromRaw + : IFromRawJson +{ + /// + public ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ModelConfigAzureApiKeyModelConfigObjectProviderOptionsAzure.FromRawUnchecked(rawData); +} + [JsonConverter( typeof(JsonModelConverter< ModelConfigGenericModelConfigObject, diff --git a/src/Stagehand/Models/Sessions/SessionActParams.cs b/src/Stagehand/Models/Sessions/SessionActParams.cs index b3d92a2..6a6906d 100644 --- a/src/Stagehand/Models/Sessions/SessionActParams.cs +++ b/src/Stagehand/Models/Sessions/SessionActParams.cs @@ -604,6 +604,8 @@ public string? ModelName { return Match( vertexModelConfigObject: (x) => x.ModelName, + azureEntraModelConfigObject: (x) => x.ModelName, + azureApiKeyModelConfigObject: (x) => x.ModelName, genericModelConfigObject: (x) => x.ModelName, @string: (_) => null ); @@ -616,6 +618,8 @@ public string? ApiKey { return Match( vertexModelConfigObject: (x) => x.ApiKey, + azureEntraModelConfigObject: (_) => null, + azureApiKeyModelConfigObject: (x) => x.ApiKey, genericModelConfigObject: (x) => x.ApiKey, @string: (_) => null ); @@ -628,6 +632,8 @@ public string? BaseUrl { return Match( vertexModelConfigObject: (x) => x.BaseUrl, + azureEntraModelConfigObject: (x) => x.BaseUrl, + azureApiKeyModelConfigObject: (x) => x.BaseUrl, genericModelConfigObject: (x) => x.BaseUrl, @string: (_) => null ); @@ -640,6 +646,18 @@ public Model(VertexModelConfigObject value, JsonElement? element = null) this._element = element; } + public Model(AzureEntraModelConfigObject value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public Model(AzureApiKeyModelConfigObject value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + public Model(GenericModelConfigObject value, JsonElement? element = null) { this.Value = value; @@ -680,6 +698,52 @@ public bool TryPickVertexModelConfigObject( return value != null; } + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAzureEntraModelConfigObject(out var value)) { + /// // `value` is of type `AzureEntraModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAzureEntraModelConfigObject( + [NotNullWhen(true)] out AzureEntraModelConfigObject? value + ) + { + value = this.Value as AzureEntraModelConfigObject; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAzureApiKeyModelConfigObject(out var value)) { + /// // `value` is of type `AzureApiKeyModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAzureApiKeyModelConfigObject( + [NotNullWhen(true)] out AzureApiKeyModelConfigObject? value + ) + { + value = this.Value as AzureApiKeyModelConfigObject; + return value != null; + } + /// /// Returns true and sets the out parameter if the instance was constructed with a variant of /// type . @@ -739,6 +803,8 @@ public bool TryPickString([NotNullWhen(true)] out string? value) /// /// instance.Switch( /// (VertexModelConfigObject value) => {...}, + /// (AzureEntraModelConfigObject value) => {...}, + /// (AzureApiKeyModelConfigObject value) => {...}, /// (GenericModelConfigObject value) => {...}, /// (string value) => {...} /// ); @@ -747,6 +813,8 @@ public bool TryPickString([NotNullWhen(true)] out string? value) /// public void Switch( System::Action vertexModelConfigObject, + System::Action azureEntraModelConfigObject, + System::Action azureApiKeyModelConfigObject, System::Action genericModelConfigObject, System::Action @string ) @@ -756,6 +824,12 @@ public void Switch( case VertexModelConfigObject value: vertexModelConfigObject(value); break; + case AzureEntraModelConfigObject value: + azureEntraModelConfigObject(value); + break; + case AzureApiKeyModelConfigObject value: + azureApiKeyModelConfigObject(value); + break; case GenericModelConfigObject value: genericModelConfigObject(value); break; @@ -783,6 +857,8 @@ public void Switch( /// /// var result = instance.Match( /// (VertexModelConfigObject value) => {...}, + /// (AzureEntraModelConfigObject value) => {...}, + /// (AzureApiKeyModelConfigObject value) => {...}, /// (GenericModelConfigObject value) => {...}, /// (string value) => {...} /// ); @@ -791,6 +867,8 @@ public void Switch( /// public T Match( System::Func vertexModelConfigObject, + System::Func azureEntraModelConfigObject, + System::Func azureApiKeyModelConfigObject, System::Func genericModelConfigObject, System::Func @string ) @@ -798,6 +876,8 @@ public T Match( return this.Value switch { VertexModelConfigObject value => vertexModelConfigObject(value), + AzureEntraModelConfigObject value => azureEntraModelConfigObject(value), + AzureApiKeyModelConfigObject value => azureApiKeyModelConfigObject(value), GenericModelConfigObject value => genericModelConfigObject(value), string value => @string(value), _ => throw new StagehandInvalidDataException("Data did not match any variant of Model"), @@ -806,6 +886,10 @@ public T Match( public static implicit operator Model(VertexModelConfigObject value) => new(value); + public static implicit operator Model(AzureEntraModelConfigObject value) => new(value); + + public static implicit operator Model(AzureApiKeyModelConfigObject value) => new(value); + public static implicit operator Model(GenericModelConfigObject value) => new(value); public static implicit operator Model(string value) => new(value); @@ -828,6 +912,8 @@ public override void Validate() } this.Switch( (vertexModelConfigObject) => vertexModelConfigObject.Validate(), + (azureEntraModelConfigObject) => azureEntraModelConfigObject.Validate(), + (azureApiKeyModelConfigObject) => azureApiKeyModelConfigObject.Validate(), (genericModelConfigObject) => genericModelConfigObject.Validate(), (_) => { } ); @@ -854,8 +940,10 @@ int VariantIndex() return this.Value switch { VertexModelConfigObject _ => 0, - GenericModelConfigObject _ => 1, - string _ => 2, + AzureEntraModelConfigObject _ => 1, + AzureApiKeyModelConfigObject _ => 2, + GenericModelConfigObject _ => 3, + string _ => 4, _ => -1, }; } @@ -887,6 +975,40 @@ JsonSerializerOptions options // ignore } + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + try { var deserialized = JsonSerializer.Deserialize( @@ -1982,6 +2104,930 @@ public Vertex FromRawUnchecked(IReadOnlyDictionary rawData) Vertex.FromRawUnchecked(rawData); } +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class AzureEntraModelConfigObject : JsonModel +{ + /// + /// Azure provider authentication configuration + /// + public required AzureEntraModelConfigObjectAuth Auth + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("auth"); + } + init { this._rawData.Set("auth", value); } + } + + /// + /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + /// + public required string ModelName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("modelName"); + } + init { this._rawData.Set("modelName", value); } + } + + /// + /// Azure OpenAI model provider + /// + public JsonElement Provider + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("provider"); + } + init { this._rawData.Set("provider", value); } + } + + /// + /// Azure provider-specific model configuration + /// + public required AzureEntraModelConfigObjectProviderOptions ProviderOptions + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "providerOptions" + ); + } + init { this._rawData.Set("providerOptions", value); } + } + + /// + /// Base URL for the model provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the model provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + public override void Validate() + { + this.Auth.Validate(); + _ = this.ModelName; + if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("azure"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + this.ProviderOptions.Validate(); + _ = this.BaseUrl; + _ = this.Headers; + } + + public AzureEntraModelConfigObject() + { + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public AzureEntraModelConfigObject(AzureEntraModelConfigObject azureEntraModelConfigObject) + : base(azureEntraModelConfigObject) { } +#pragma warning restore CS8618 + + public AzureEntraModelConfigObject(IReadOnlyDictionary rawData) + { + this._rawData = new(rawData); + + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AzureEntraModelConfigObject(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static AzureEntraModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AzureEntraModelConfigObjectFromRaw : IFromRawJson +{ + /// + public AzureEntraModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AzureEntraModelConfigObject.FromRawUnchecked(rawData); +} + +/// +/// Azure provider authentication configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + AzureEntraModelConfigObjectAuth, + AzureEntraModelConfigObjectAuthFromRaw + >) +)] +public sealed record class AzureEntraModelConfigObjectAuth : JsonModel +{ + /// + /// Microsoft Entra ID bearer token for Azure OpenAI + /// + public required string Token + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("token"); + } + init { this._rawData.Set("token", value); } + } + + /// + /// Use a Microsoft Entra ID bearer token for authentication + /// + public JsonElement Type + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("type"); + } + init { this._rawData.Set("type", value); } + } + + /// + public override void Validate() + { + _ = this.Token; + if (!JsonElement.DeepEquals(this.Type, JsonSerializer.SerializeToElement("azureEntraId"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + } + + public AzureEntraModelConfigObjectAuth() + { + this.Type = JsonSerializer.SerializeToElement("azureEntraId"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public AzureEntraModelConfigObjectAuth( + AzureEntraModelConfigObjectAuth azureEntraModelConfigObjectAuth + ) + : base(azureEntraModelConfigObjectAuth) { } +#pragma warning restore CS8618 + + public AzureEntraModelConfigObjectAuth(IReadOnlyDictionary rawData) + { + this._rawData = new(rawData); + + this.Type = JsonSerializer.SerializeToElement("azureEntraId"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AzureEntraModelConfigObjectAuth(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static AzureEntraModelConfigObjectAuth FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public AzureEntraModelConfigObjectAuth(string token) + : this() + { + this.Token = token; + } +} + +class AzureEntraModelConfigObjectAuthFromRaw : IFromRawJson +{ + /// + public AzureEntraModelConfigObjectAuth FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AzureEntraModelConfigObjectAuth.FromRawUnchecked(rawData); +} + +/// +/// Azure provider-specific model configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + AzureEntraModelConfigObjectProviderOptions, + AzureEntraModelConfigObjectProviderOptionsFromRaw + >) +)] +public sealed record class AzureEntraModelConfigObjectProviderOptions : JsonModel +{ + /// + /// Azure OpenAI provider-specific settings + /// + public required Azure Azure + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("azure"); + } + init { this._rawData.Set("azure", value); } + } + + /// + public override void Validate() + { + this.Azure.Validate(); + } + + public AzureEntraModelConfigObjectProviderOptions() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public AzureEntraModelConfigObjectProviderOptions( + AzureEntraModelConfigObjectProviderOptions azureEntraModelConfigObjectProviderOptions + ) + : base(azureEntraModelConfigObjectProviderOptions) { } +#pragma warning restore CS8618 + + public AzureEntraModelConfigObjectProviderOptions( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AzureEntraModelConfigObjectProviderOptions(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static AzureEntraModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public AzureEntraModelConfigObjectProviderOptions(Azure azure) + : this() + { + this.Azure = azure; + } +} + +class AzureEntraModelConfigObjectProviderOptionsFromRaw + : IFromRawJson +{ + /// + public AzureEntraModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AzureEntraModelConfigObjectProviderOptions.FromRawUnchecked(rawData); +} + +/// +/// Azure OpenAI provider-specific settings +/// +[JsonConverter(typeof(JsonModelConverter))] +public sealed record class Azure : JsonModel +{ + /// + /// Azure OpenAI API version + /// + public string? ApiVersion + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiVersion"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiVersion", value); + } + } + + /// + /// Base URL for the Azure OpenAI provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the Azure OpenAI provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + /// Azure OpenAI resource name + /// + public string? ResourceName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("resourceName"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("resourceName", value); + } + } + + /// + /// Whether to use deployment-based Azure OpenAI URLs + /// + public bool? UseDeploymentBasedUrls + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableStruct("useDeploymentBasedUrls"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("useDeploymentBasedUrls", value); + } + } + + /// + public override void Validate() + { + _ = this.ApiVersion; + _ = this.BaseUrl; + _ = this.Headers; + _ = this.ResourceName; + _ = this.UseDeploymentBasedUrls; + } + + public Azure() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public Azure(Azure azure) + : base(azure) { } +#pragma warning restore CS8618 + + public Azure(IReadOnlyDictionary rawData) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + Azure(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static Azure FromRawUnchecked(IReadOnlyDictionary rawData) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AzureFromRaw : IFromRawJson +{ + /// + public Azure FromRawUnchecked(IReadOnlyDictionary rawData) => + Azure.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter) +)] +public sealed record class AzureApiKeyModelConfigObject : JsonModel +{ + /// + /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + /// + public required string ModelName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("modelName"); + } + init { this._rawData.Set("modelName", value); } + } + + /// + /// Azure OpenAI model provider + /// + public JsonElement Provider + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("provider"); + } + init { this._rawData.Set("provider", value); } + } + + /// + /// Azure provider-specific model configuration + /// + public required AzureApiKeyModelConfigObjectProviderOptions ProviderOptions + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "providerOptions" + ); + } + init { this._rawData.Set("providerOptions", value); } + } + + /// + /// API key for the model provider + /// + public string? ApiKey + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiKey"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiKey", value); + } + } + + /// + /// Base URL for the model provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the model provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + public override void Validate() + { + _ = this.ModelName; + if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("azure"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + this.ProviderOptions.Validate(); + _ = this.ApiKey; + _ = this.BaseUrl; + _ = this.Headers; + } + + public AzureApiKeyModelConfigObject() + { + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public AzureApiKeyModelConfigObject(AzureApiKeyModelConfigObject azureApiKeyModelConfigObject) + : base(azureApiKeyModelConfigObject) { } +#pragma warning restore CS8618 + + public AzureApiKeyModelConfigObject(IReadOnlyDictionary rawData) + { + this._rawData = new(rawData); + + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AzureApiKeyModelConfigObject(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static AzureApiKeyModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AzureApiKeyModelConfigObjectFromRaw : IFromRawJson +{ + /// + public AzureApiKeyModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AzureApiKeyModelConfigObject.FromRawUnchecked(rawData); +} + +/// +/// Azure provider-specific model configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + AzureApiKeyModelConfigObjectProviderOptions, + AzureApiKeyModelConfigObjectProviderOptionsFromRaw + >) +)] +public sealed record class AzureApiKeyModelConfigObjectProviderOptions : JsonModel +{ + /// + /// Azure OpenAI provider-specific settings + /// + public required AzureApiKeyModelConfigObjectProviderOptionsAzure Azure + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "azure" + ); + } + init { this._rawData.Set("azure", value); } + } + + /// + public override void Validate() + { + this.Azure.Validate(); + } + + public AzureApiKeyModelConfigObjectProviderOptions() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public AzureApiKeyModelConfigObjectProviderOptions( + AzureApiKeyModelConfigObjectProviderOptions azureApiKeyModelConfigObjectProviderOptions + ) + : base(azureApiKeyModelConfigObjectProviderOptions) { } +#pragma warning restore CS8618 + + public AzureApiKeyModelConfigObjectProviderOptions( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AzureApiKeyModelConfigObjectProviderOptions(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static AzureApiKeyModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public AzureApiKeyModelConfigObjectProviderOptions( + AzureApiKeyModelConfigObjectProviderOptionsAzure azure + ) + : this() + { + this.Azure = azure; + } +} + +class AzureApiKeyModelConfigObjectProviderOptionsFromRaw + : IFromRawJson +{ + /// + public AzureApiKeyModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AzureApiKeyModelConfigObjectProviderOptions.FromRawUnchecked(rawData); +} + +/// +/// Azure OpenAI provider-specific settings +/// +[JsonConverter( + typeof(JsonModelConverter< + AzureApiKeyModelConfigObjectProviderOptionsAzure, + AzureApiKeyModelConfigObjectProviderOptionsAzureFromRaw + >) +)] +public sealed record class AzureApiKeyModelConfigObjectProviderOptionsAzure : JsonModel +{ + /// + /// Azure OpenAI API version + /// + public string? ApiVersion + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiVersion"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiVersion", value); + } + } + + /// + /// Base URL for the Azure OpenAI provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the Azure OpenAI provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + /// Azure OpenAI resource name + /// + public string? ResourceName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("resourceName"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("resourceName", value); + } + } + + /// + /// Whether to use deployment-based Azure OpenAI URLs + /// + public bool? UseDeploymentBasedUrls + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableStruct("useDeploymentBasedUrls"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("useDeploymentBasedUrls", value); + } + } + + /// + public override void Validate() + { + _ = this.ApiVersion; + _ = this.BaseUrl; + _ = this.Headers; + _ = this.ResourceName; + _ = this.UseDeploymentBasedUrls; + } + + public AzureApiKeyModelConfigObjectProviderOptionsAzure() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public AzureApiKeyModelConfigObjectProviderOptionsAzure( + AzureApiKeyModelConfigObjectProviderOptionsAzure azureApiKeyModelConfigObjectProviderOptionsAzure + ) + : base(azureApiKeyModelConfigObjectProviderOptionsAzure) { } +#pragma warning restore CS8618 + + public AzureApiKeyModelConfigObjectProviderOptionsAzure( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AzureApiKeyModelConfigObjectProviderOptionsAzure(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static AzureApiKeyModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AzureApiKeyModelConfigObjectProviderOptionsAzureFromRaw + : IFromRawJson +{ + /// + public AzureApiKeyModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AzureApiKeyModelConfigObjectProviderOptionsAzure.FromRawUnchecked(rawData); +} + [JsonConverter( typeof(JsonModelConverter) )] diff --git a/src/Stagehand/Models/Sessions/SessionExecuteParams.cs b/src/Stagehand/Models/Sessions/SessionExecuteParams.cs index 5128db2..d8de35d 100644 --- a/src/Stagehand/Models/Sessions/SessionExecuteParams.cs +++ b/src/Stagehand/Models/Sessions/SessionExecuteParams.cs @@ -433,6 +433,8 @@ public string? ModelName { return Match( vertexModelConfigObject: (x) => x.ModelName, + azureEntraModelConfigObject: (x) => x.ModelName, + azureApiKeyModelConfigObject: (x) => x.ModelName, genericModelConfigObject: (x) => x.ModelName, @string: (_) => null ); @@ -445,6 +447,8 @@ public string? ApiKey { return Match( vertexModelConfigObject: (x) => x.ApiKey, + azureEntraModelConfigObject: (_) => null, + azureApiKeyModelConfigObject: (x) => x.ApiKey, genericModelConfigObject: (x) => x.ApiKey, @string: (_) => null ); @@ -457,6 +461,8 @@ public string? BaseUrl { return Match( vertexModelConfigObject: (x) => x.BaseUrl, + azureEntraModelConfigObject: (x) => x.BaseUrl, + azureApiKeyModelConfigObject: (x) => x.BaseUrl, genericModelConfigObject: (x) => x.BaseUrl, @string: (_) => null ); @@ -469,6 +475,24 @@ public ExecutionModel(ExecutionModelVertexModelConfigObject value, JsonElement? this._element = element; } + public ExecutionModel( + ExecutionModelAzureEntraModelConfigObject value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public ExecutionModel( + ExecutionModelAzureApiKeyModelConfigObject value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + public ExecutionModel(ExecutionModelGenericModelConfigObject value, JsonElement? element = null) { this.Value = value; @@ -509,6 +533,52 @@ public bool TryPickVertexModelConfigObject( return value != null; } + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAzureEntraModelConfigObject(out var value)) { + /// // `value` is of type `ExecutionModelAzureEntraModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAzureEntraModelConfigObject( + [NotNullWhen(true)] out ExecutionModelAzureEntraModelConfigObject? value + ) + { + value = this.Value as ExecutionModelAzureEntraModelConfigObject; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAzureApiKeyModelConfigObject(out var value)) { + /// // `value` is of type `ExecutionModelAzureApiKeyModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAzureApiKeyModelConfigObject( + [NotNullWhen(true)] out ExecutionModelAzureApiKeyModelConfigObject? value + ) + { + value = this.Value as ExecutionModelAzureApiKeyModelConfigObject; + return value != null; + } + /// /// Returns true and sets the out parameter if the instance was constructed with a variant of /// type . @@ -568,6 +638,8 @@ public bool TryPickString([NotNullWhen(true)] out string? value) /// /// instance.Switch( /// (ExecutionModelVertexModelConfigObject value) => {...}, + /// (ExecutionModelAzureEntraModelConfigObject value) => {...}, + /// (ExecutionModelAzureApiKeyModelConfigObject value) => {...}, /// (ExecutionModelGenericModelConfigObject value) => {...}, /// (string value) => {...} /// ); @@ -576,6 +648,8 @@ public bool TryPickString([NotNullWhen(true)] out string? value) /// public void Switch( System::Action vertexModelConfigObject, + System::Action azureEntraModelConfigObject, + System::Action azureApiKeyModelConfigObject, System::Action genericModelConfigObject, System::Action @string ) @@ -585,6 +659,12 @@ public void Switch( case ExecutionModelVertexModelConfigObject value: vertexModelConfigObject(value); break; + case ExecutionModelAzureEntraModelConfigObject value: + azureEntraModelConfigObject(value); + break; + case ExecutionModelAzureApiKeyModelConfigObject value: + azureApiKeyModelConfigObject(value); + break; case ExecutionModelGenericModelConfigObject value: genericModelConfigObject(value); break; @@ -614,6 +694,8 @@ public void Switch( /// /// var result = instance.Match( /// (ExecutionModelVertexModelConfigObject value) => {...}, + /// (ExecutionModelAzureEntraModelConfigObject value) => {...}, + /// (ExecutionModelAzureApiKeyModelConfigObject value) => {...}, /// (ExecutionModelGenericModelConfigObject value) => {...}, /// (string value) => {...} /// ); @@ -622,6 +704,8 @@ public void Switch( /// public T Match( System::Func vertexModelConfigObject, + System::Func azureEntraModelConfigObject, + System::Func azureApiKeyModelConfigObject, System::Func genericModelConfigObject, System::Func @string ) @@ -629,6 +713,8 @@ public T Match( return this.Value switch { ExecutionModelVertexModelConfigObject value => vertexModelConfigObject(value), + ExecutionModelAzureEntraModelConfigObject value => azureEntraModelConfigObject(value), + ExecutionModelAzureApiKeyModelConfigObject value => azureApiKeyModelConfigObject(value), ExecutionModelGenericModelConfigObject value => genericModelConfigObject(value), string value => @string(value), _ => throw new StagehandInvalidDataException( @@ -640,6 +726,14 @@ public T Match( public static implicit operator ExecutionModel(ExecutionModelVertexModelConfigObject value) => new(value); + public static implicit operator ExecutionModel( + ExecutionModelAzureEntraModelConfigObject value + ) => new(value); + + public static implicit operator ExecutionModel( + ExecutionModelAzureApiKeyModelConfigObject value + ) => new(value); + public static implicit operator ExecutionModel(ExecutionModelGenericModelConfigObject value) => new(value); @@ -665,6 +759,8 @@ public override void Validate() } this.Switch( (vertexModelConfigObject) => vertexModelConfigObject.Validate(), + (azureEntraModelConfigObject) => azureEntraModelConfigObject.Validate(), + (azureApiKeyModelConfigObject) => azureApiKeyModelConfigObject.Validate(), (genericModelConfigObject) => genericModelConfigObject.Validate(), (_) => { } ); @@ -691,8 +787,10 @@ int VariantIndex() return this.Value switch { ExecutionModelVertexModelConfigObject _ => 0, - ExecutionModelGenericModelConfigObject _ => 1, - string _ => 2, + ExecutionModelAzureEntraModelConfigObject _ => 1, + ExecutionModelAzureApiKeyModelConfigObject _ => 2, + ExecutionModelGenericModelConfigObject _ => 3, + string _ => 4, _ => -1, }; } @@ -724,6 +822,42 @@ JsonSerializerOptions options // ignore } + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + try { var deserialized = JsonSerializer.Deserialize( @@ -1924,12 +2058,27 @@ IReadOnlyDictionary rawData [JsonConverter( typeof(JsonModelConverter< - ExecutionModelGenericModelConfigObject, - ExecutionModelGenericModelConfigObjectFromRaw + ExecutionModelAzureEntraModelConfigObject, + ExecutionModelAzureEntraModelConfigObjectFromRaw >) )] -public sealed record class ExecutionModelGenericModelConfigObject : JsonModel +public sealed record class ExecutionModelAzureEntraModelConfigObject : JsonModel { + /// + /// Azure provider authentication configuration + /// + public required ExecutionModelAzureEntraModelConfigObjectAuth Auth + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "auth" + ); + } + init { this._rawData.Set("auth", value); } + } + /// /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') /// @@ -1944,24 +2093,31 @@ public required string ModelName } /// - /// API key for the model provider + /// Azure OpenAI model provider /// - public string? ApiKey + public JsonElement Provider { get { this._rawData.Freeze(); - return this._rawData.GetNullableClass("apiKey"); + return this._rawData.GetNotNullStruct("provider"); } - init - { - if (value == null) - { - return; - } + init { this._rawData.Set("provider", value); } + } - this._rawData.Set("apiKey", value); + /// + /// Azure provider-specific model configuration + /// + public required ExecutionModelAzureEntraModelConfigObjectProviderOptions ProviderOptions + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "providerOptions" + ); } + init { this._rawData.Set("providerOptions", value); } } /// @@ -2009,64 +2165,147 @@ public IReadOnlyDictionary? Headers } } + /// + public override void Validate() + { + this.Auth.Validate(); + _ = this.ModelName; + if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("azure"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + this.ProviderOptions.Validate(); + _ = this.BaseUrl; + _ = this.Headers; + } + + public ExecutionModelAzureEntraModelConfigObject() + { + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ExecutionModelAzureEntraModelConfigObject( + ExecutionModelAzureEntraModelConfigObject executionModelAzureEntraModelConfigObject + ) + : base(executionModelAzureEntraModelConfigObject) { } +#pragma warning restore CS8618 + + public ExecutionModelAzureEntraModelConfigObject( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExecutionModelAzureEntraModelConfigObject(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ExecutionModelAzureEntraModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ExecutionModelAzureEntraModelConfigObjectFromRaw + : IFromRawJson +{ + /// + public ExecutionModelAzureEntraModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ExecutionModelAzureEntraModelConfigObject.FromRawUnchecked(rawData); +} + +/// +/// Azure provider authentication configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + ExecutionModelAzureEntraModelConfigObjectAuth, + ExecutionModelAzureEntraModelConfigObjectAuthFromRaw + >) +)] +public sealed record class ExecutionModelAzureEntraModelConfigObjectAuth : JsonModel +{ /// - /// AI provider for the model (or provide a baseURL endpoint instead) + /// Microsoft Entra ID bearer token for Azure OpenAI /// - public ApiEnum? Provider + public required string Token { get { this._rawData.Freeze(); - return this._rawData.GetNullableClass< - ApiEnum - >("provider"); + return this._rawData.GetNotNullClass("token"); } - init - { - if (value == null) - { - return; - } + init { this._rawData.Set("token", value); } + } - this._rawData.Set("provider", value); + /// + /// Use a Microsoft Entra ID bearer token for authentication + /// + public JsonElement Type + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("type"); } + init { this._rawData.Set("type", value); } } /// public override void Validate() { - _ = this.ModelName; - _ = this.ApiKey; - _ = this.BaseUrl; - _ = this.Headers; - this.Provider?.Validate(); + _ = this.Token; + if (!JsonElement.DeepEquals(this.Type, JsonSerializer.SerializeToElement("azureEntraId"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } } - public ExecutionModelGenericModelConfigObject() { } + public ExecutionModelAzureEntraModelConfigObjectAuth() + { + this.Type = JsonSerializer.SerializeToElement("azureEntraId"); + } #pragma warning disable CS8618 [SetsRequiredMembers] - public ExecutionModelGenericModelConfigObject( - ExecutionModelGenericModelConfigObject executionModelGenericModelConfigObject + public ExecutionModelAzureEntraModelConfigObjectAuth( + ExecutionModelAzureEntraModelConfigObjectAuth executionModelAzureEntraModelConfigObjectAuth ) - : base(executionModelGenericModelConfigObject) { } + : base(executionModelAzureEntraModelConfigObjectAuth) { } #pragma warning restore CS8618 - public ExecutionModelGenericModelConfigObject(IReadOnlyDictionary rawData) + public ExecutionModelAzureEntraModelConfigObjectAuth( + IReadOnlyDictionary rawData + ) { this._rawData = new(rawData); + + this.Type = JsonSerializer.SerializeToElement("azureEntraId"); } #pragma warning disable CS8618 [SetsRequiredMembers] - ExecutionModelGenericModelConfigObject(FrozenDictionary rawData) + ExecutionModelAzureEntraModelConfigObjectAuth(FrozenDictionary rawData) { this._rawData = new(rawData); } #pragma warning restore CS8618 - /// - public static ExecutionModelGenericModelConfigObject FromRawUnchecked( + /// + public static ExecutionModelAzureEntraModelConfigObjectAuth FromRawUnchecked( IReadOnlyDictionary rawData ) { @@ -2074,93 +2313,2132 @@ IReadOnlyDictionary rawData } [SetsRequiredMembers] - public ExecutionModelGenericModelConfigObject(string modelName) + public ExecutionModelAzureEntraModelConfigObjectAuth(string token) : this() { - this.ModelName = modelName; + this.Token = token; } } -class ExecutionModelGenericModelConfigObjectFromRaw - : IFromRawJson +class ExecutionModelAzureEntraModelConfigObjectAuthFromRaw + : IFromRawJson { /// - public ExecutionModelGenericModelConfigObject FromRawUnchecked( + public ExecutionModelAzureEntraModelConfigObjectAuth FromRawUnchecked( IReadOnlyDictionary rawData - ) => ExecutionModelGenericModelConfigObject.FromRawUnchecked(rawData); + ) => ExecutionModelAzureEntraModelConfigObjectAuth.FromRawUnchecked(rawData); } /// -/// AI provider for the model (or provide a baseURL endpoint instead) +/// Azure provider-specific model configuration /// -[JsonConverter(typeof(ExecutionModelGenericModelConfigObjectProviderConverter))] -public enum ExecutionModelGenericModelConfigObjectProvider -{ - OpenAI, - Anthropic, - Google, - Microsoft, - Bedrock, -} - -sealed class ExecutionModelGenericModelConfigObjectProviderConverter - : JsonConverter +[JsonConverter( + typeof(JsonModelConverter< + ExecutionModelAzureEntraModelConfigObjectProviderOptions, + ExecutionModelAzureEntraModelConfigObjectProviderOptionsFromRaw + >) +)] +public sealed record class ExecutionModelAzureEntraModelConfigObjectProviderOptions : JsonModel { - public override ExecutionModelGenericModelConfigObjectProvider Read( - ref Utf8JsonReader reader, - System::Type typeToConvert, - JsonSerializerOptions options - ) + /// + /// Azure OpenAI provider-specific settings + /// + public required ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure Azure { - return JsonSerializer.Deserialize(ref reader, options) switch + get { - "openai" => ExecutionModelGenericModelConfigObjectProvider.OpenAI, - "anthropic" => ExecutionModelGenericModelConfigObjectProvider.Anthropic, - "google" => ExecutionModelGenericModelConfigObjectProvider.Google, - "microsoft" => ExecutionModelGenericModelConfigObjectProvider.Microsoft, - "bedrock" => ExecutionModelGenericModelConfigObjectProvider.Bedrock, - _ => (ExecutionModelGenericModelConfigObjectProvider)(-1), - }; + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "azure" + ); + } + init { this._rawData.Set("azure", value); } + } + + /// + public override void Validate() + { + this.Azure.Validate(); + } + + public ExecutionModelAzureEntraModelConfigObjectProviderOptions() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ExecutionModelAzureEntraModelConfigObjectProviderOptions( + ExecutionModelAzureEntraModelConfigObjectProviderOptions executionModelAzureEntraModelConfigObjectProviderOptions + ) + : base(executionModelAzureEntraModelConfigObjectProviderOptions) { } +#pragma warning restore CS8618 + + public ExecutionModelAzureEntraModelConfigObjectProviderOptions( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExecutionModelAzureEntraModelConfigObjectProviderOptions( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ExecutionModelAzureEntraModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ExecutionModelAzureEntraModelConfigObjectProviderOptions( + ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure azure + ) + : this() + { + this.Azure = azure; + } +} + +class ExecutionModelAzureEntraModelConfigObjectProviderOptionsFromRaw + : IFromRawJson +{ + /// + public ExecutionModelAzureEntraModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ExecutionModelAzureEntraModelConfigObjectProviderOptions.FromRawUnchecked(rawData); +} + +/// +/// Azure OpenAI provider-specific settings +/// +[JsonConverter( + typeof(JsonModelConverter< + ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure, + ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzureFromRaw + >) +)] +public sealed record class ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure : JsonModel +{ + /// + /// Azure OpenAI API version + /// + public string? ApiVersion + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiVersion"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiVersion", value); + } + } + + /// + /// Base URL for the Azure OpenAI provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the Azure OpenAI provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + /// Azure OpenAI resource name + /// + public string? ResourceName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("resourceName"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("resourceName", value); + } + } + + /// + /// Whether to use deployment-based Azure OpenAI URLs + /// + public bool? UseDeploymentBasedUrls + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableStruct("useDeploymentBasedUrls"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("useDeploymentBasedUrls", value); + } + } + + /// + public override void Validate() + { + _ = this.ApiVersion; + _ = this.BaseUrl; + _ = this.Headers; + _ = this.ResourceName; + _ = this.UseDeploymentBasedUrls; + } + + public ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure( + ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure executionModelAzureEntraModelConfigObjectProviderOptionsAzure + ) + : base(executionModelAzureEntraModelConfigObjectProviderOptionsAzure) { } +#pragma warning restore CS8618 + + public ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzureFromRaw + : IFromRawJson +{ + /// + public ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ExecutionModelAzureEntraModelConfigObjectProviderOptionsAzure.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + ExecutionModelAzureApiKeyModelConfigObject, + ExecutionModelAzureApiKeyModelConfigObjectFromRaw + >) +)] +public sealed record class ExecutionModelAzureApiKeyModelConfigObject : JsonModel +{ + /// + /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + /// + public required string ModelName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("modelName"); + } + init { this._rawData.Set("modelName", value); } + } + + /// + /// Azure OpenAI model provider + /// + public JsonElement Provider + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("provider"); + } + init { this._rawData.Set("provider", value); } + } + + /// + /// Azure provider-specific model configuration + /// + public required ExecutionModelAzureApiKeyModelConfigObjectProviderOptions ProviderOptions + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "providerOptions" + ); + } + init { this._rawData.Set("providerOptions", value); } + } + + /// + /// API key for the model provider + /// + public string? ApiKey + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiKey"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiKey", value); + } + } + + /// + /// Base URL for the model provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the model provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + public override void Validate() + { + _ = this.ModelName; + if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("azure"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + this.ProviderOptions.Validate(); + _ = this.ApiKey; + _ = this.BaseUrl; + _ = this.Headers; + } + + public ExecutionModelAzureApiKeyModelConfigObject() + { + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ExecutionModelAzureApiKeyModelConfigObject( + ExecutionModelAzureApiKeyModelConfigObject executionModelAzureApiKeyModelConfigObject + ) + : base(executionModelAzureApiKeyModelConfigObject) { } +#pragma warning restore CS8618 + + public ExecutionModelAzureApiKeyModelConfigObject( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExecutionModelAzureApiKeyModelConfigObject(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ExecutionModelAzureApiKeyModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ExecutionModelAzureApiKeyModelConfigObjectFromRaw + : IFromRawJson +{ + /// + public ExecutionModelAzureApiKeyModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ExecutionModelAzureApiKeyModelConfigObject.FromRawUnchecked(rawData); +} + +/// +/// Azure provider-specific model configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + ExecutionModelAzureApiKeyModelConfigObjectProviderOptions, + ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsFromRaw + >) +)] +public sealed record class ExecutionModelAzureApiKeyModelConfigObjectProviderOptions : JsonModel +{ + /// + /// Azure OpenAI provider-specific settings + /// + public required ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure Azure + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "azure" + ); + } + init { this._rawData.Set("azure", value); } + } + + /// + public override void Validate() + { + this.Azure.Validate(); + } + + public ExecutionModelAzureApiKeyModelConfigObjectProviderOptions() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ExecutionModelAzureApiKeyModelConfigObjectProviderOptions( + ExecutionModelAzureApiKeyModelConfigObjectProviderOptions executionModelAzureApiKeyModelConfigObjectProviderOptions + ) + : base(executionModelAzureApiKeyModelConfigObjectProviderOptions) { } +#pragma warning restore CS8618 + + public ExecutionModelAzureApiKeyModelConfigObjectProviderOptions( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExecutionModelAzureApiKeyModelConfigObjectProviderOptions( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ExecutionModelAzureApiKeyModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ExecutionModelAzureApiKeyModelConfigObjectProviderOptions( + ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure azure + ) + : this() + { + this.Azure = azure; + } +} + +class ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsFromRaw + : IFromRawJson +{ + /// + public ExecutionModelAzureApiKeyModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ExecutionModelAzureApiKeyModelConfigObjectProviderOptions.FromRawUnchecked(rawData); +} + +/// +/// Azure OpenAI provider-specific settings +/// +[JsonConverter( + typeof(JsonModelConverter< + ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure, + ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzureFromRaw + >) +)] +public sealed record class ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure + : JsonModel +{ + /// + /// Azure OpenAI API version + /// + public string? ApiVersion + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiVersion"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiVersion", value); + } + } + + /// + /// Base URL for the Azure OpenAI provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the Azure OpenAI provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + /// Azure OpenAI resource name + /// + public string? ResourceName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("resourceName"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("resourceName", value); + } + } + + /// + /// Whether to use deployment-based Azure OpenAI URLs + /// + public bool? UseDeploymentBasedUrls + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableStruct("useDeploymentBasedUrls"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("useDeploymentBasedUrls", value); + } + } + + /// + public override void Validate() + { + _ = this.ApiVersion; + _ = this.BaseUrl; + _ = this.Headers; + _ = this.ResourceName; + _ = this.UseDeploymentBasedUrls; + } + + public ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure( + ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure executionModelAzureApiKeyModelConfigObjectProviderOptionsAzure + ) + : base(executionModelAzureApiKeyModelConfigObjectProviderOptionsAzure) { } +#pragma warning restore CS8618 + + public ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzureFromRaw + : IFromRawJson +{ + /// + public ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ExecutionModelAzureApiKeyModelConfigObjectProviderOptionsAzure.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + ExecutionModelGenericModelConfigObject, + ExecutionModelGenericModelConfigObjectFromRaw + >) +)] +public sealed record class ExecutionModelGenericModelConfigObject : JsonModel +{ + /// + /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + /// + public required string ModelName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("modelName"); + } + init { this._rawData.Set("modelName", value); } + } + + /// + /// API key for the model provider + /// + public string? ApiKey + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiKey"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiKey", value); + } + } + + /// + /// Base URL for the model provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the model provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + /// AI provider for the model (or provide a baseURL endpoint instead) + /// + public ApiEnum? Provider + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass< + ApiEnum + >("provider"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("provider", value); + } + } + + /// + public override void Validate() + { + _ = this.ModelName; + _ = this.ApiKey; + _ = this.BaseUrl; + _ = this.Headers; + this.Provider?.Validate(); + } + + public ExecutionModelGenericModelConfigObject() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public ExecutionModelGenericModelConfigObject( + ExecutionModelGenericModelConfigObject executionModelGenericModelConfigObject + ) + : base(executionModelGenericModelConfigObject) { } +#pragma warning restore CS8618 + + public ExecutionModelGenericModelConfigObject(IReadOnlyDictionary rawData) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + ExecutionModelGenericModelConfigObject(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static ExecutionModelGenericModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public ExecutionModelGenericModelConfigObject(string modelName) + : this() + { + this.ModelName = modelName; + } +} + +class ExecutionModelGenericModelConfigObjectFromRaw + : IFromRawJson +{ + /// + public ExecutionModelGenericModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) => ExecutionModelGenericModelConfigObject.FromRawUnchecked(rawData); +} + +/// +/// AI provider for the model (or provide a baseURL endpoint instead) +/// +[JsonConverter(typeof(ExecutionModelGenericModelConfigObjectProviderConverter))] +public enum ExecutionModelGenericModelConfigObjectProvider +{ + OpenAI, + Anthropic, + Google, + Microsoft, + Bedrock, +} + +sealed class ExecutionModelGenericModelConfigObjectProviderConverter + : JsonConverter +{ + public override ExecutionModelGenericModelConfigObjectProvider Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "openai" => ExecutionModelGenericModelConfigObjectProvider.OpenAI, + "anthropic" => ExecutionModelGenericModelConfigObjectProvider.Anthropic, + "google" => ExecutionModelGenericModelConfigObjectProvider.Google, + "microsoft" => ExecutionModelGenericModelConfigObjectProvider.Microsoft, + "bedrock" => ExecutionModelGenericModelConfigObjectProvider.Bedrock, + _ => (ExecutionModelGenericModelConfigObjectProvider)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ExecutionModelGenericModelConfigObjectProvider value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ExecutionModelGenericModelConfigObjectProvider.OpenAI => "openai", + ExecutionModelGenericModelConfigObjectProvider.Anthropic => "anthropic", + ExecutionModelGenericModelConfigObjectProvider.Google => "google", + ExecutionModelGenericModelConfigObjectProvider.Microsoft => "microsoft", + ExecutionModelGenericModelConfigObjectProvider.Bedrock => "bedrock", + _ => throw new StagehandInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Tool mode for the agent (dom, hybrid, cua). If set, overrides cua. +/// +[JsonConverter(typeof(ModeConverter))] +public enum Mode +{ + Dom, + Hybrid, + Cua, +} + +sealed class ModeConverter : JsonConverter +{ + public override Mode Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "dom" => Mode.Dom, + "hybrid" => Mode.Hybrid, + "cua" => Mode.Cua, + _ => (Mode)(-1), + }; + } + + public override void Write(Utf8JsonWriter writer, Mode value, JsonSerializerOptions options) + { + JsonSerializer.Serialize( + writer, + value switch + { + Mode.Dom => "dom", + Mode.Hybrid => "hybrid", + Mode.Cua => "cua", + _ => throw new StagehandInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + +/// +/// Model configuration object or model name string (e.g., 'openai/gpt-5-nano') +/// +[JsonConverter(typeof(AgentConfigModelConverter))] +public record class AgentConfigModel : ModelBase +{ + public object? Value { get; } = null; + + JsonElement? _element = null; + + public JsonElement Json + { + get + { + return this._element ??= JsonSerializer.SerializeToElement( + this.Value, + ModelBase.SerializerOptions + ); + } + } + + public string? ModelName + { + get + { + return Match( + vertexModelConfigObject: (x) => x.ModelName, + azureEntraModelConfigObject: (x) => x.ModelName, + azureApiKeyModelConfigObject: (x) => x.ModelName, + genericModelConfigObject: (x) => x.ModelName, + @string: (_) => null + ); + } + } + + public string? ApiKey + { + get + { + return Match( + vertexModelConfigObject: (x) => x.ApiKey, + azureEntraModelConfigObject: (_) => null, + azureApiKeyModelConfigObject: (x) => x.ApiKey, + genericModelConfigObject: (x) => x.ApiKey, + @string: (_) => null + ); + } + } + + public string? BaseUrl + { + get + { + return Match( + vertexModelConfigObject: (x) => x.BaseUrl, + azureEntraModelConfigObject: (x) => x.BaseUrl, + azureApiKeyModelConfigObject: (x) => x.BaseUrl, + genericModelConfigObject: (x) => x.BaseUrl, + @string: (_) => null + ); + } + } + + public AgentConfigModel( + AgentConfigModelVertexModelConfigObject value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public AgentConfigModel( + AgentConfigModelAzureEntraModelConfigObject value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public AgentConfigModel( + AgentConfigModelAzureApiKeyModelConfigObject value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public AgentConfigModel( + AgentConfigModelGenericModelConfigObject value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public AgentConfigModel(string value, JsonElement? element = null) + { + this.Value = value; + this._element = element; + } + + public AgentConfigModel(JsonElement element) + { + this._element = element; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickVertexModelConfigObject(out var value)) { + /// // `value` is of type `AgentConfigModelVertexModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickVertexModelConfigObject( + [NotNullWhen(true)] out AgentConfigModelVertexModelConfigObject? value + ) + { + value = this.Value as AgentConfigModelVertexModelConfigObject; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAzureEntraModelConfigObject(out var value)) { + /// // `value` is of type `AgentConfigModelAzureEntraModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAzureEntraModelConfigObject( + [NotNullWhen(true)] out AgentConfigModelAzureEntraModelConfigObject? value + ) + { + value = this.Value as AgentConfigModelAzureEntraModelConfigObject; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAzureApiKeyModelConfigObject(out var value)) { + /// // `value` is of type `AgentConfigModelAzureApiKeyModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAzureApiKeyModelConfigObject( + [NotNullWhen(true)] out AgentConfigModelAzureApiKeyModelConfigObject? value + ) + { + value = this.Value as AgentConfigModelAzureApiKeyModelConfigObject; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickGenericModelConfigObject(out var value)) { + /// // `value` is of type `AgentConfigModelGenericModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickGenericModelConfigObject( + [NotNullWhen(true)] out AgentConfigModelGenericModelConfigObject? value + ) + { + value = this.Value as AgentConfigModelGenericModelConfigObject; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickString(out var value)) { + /// // `value` is of type `string` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickString([NotNullWhen(true)] out string? value) + { + value = this.Value as string; + return value != null; + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you need your function parameters to return something. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// instance.Switch( + /// (AgentConfigModelVertexModelConfigObject value) => {...}, + /// (AgentConfigModelAzureEntraModelConfigObject value) => {...}, + /// (AgentConfigModelAzureApiKeyModelConfigObject value) => {...}, + /// (AgentConfigModelGenericModelConfigObject value) => {...}, + /// (string value) => {...} + /// ); + /// + /// + /// + public void Switch( + System::Action vertexModelConfigObject, + System::Action azureEntraModelConfigObject, + System::Action azureApiKeyModelConfigObject, + System::Action genericModelConfigObject, + System::Action @string + ) + { + switch (this.Value) + { + case AgentConfigModelVertexModelConfigObject value: + vertexModelConfigObject(value); + break; + case AgentConfigModelAzureEntraModelConfigObject value: + azureEntraModelConfigObject(value); + break; + case AgentConfigModelAzureApiKeyModelConfigObject value: + azureApiKeyModelConfigObject(value); + break; + case AgentConfigModelGenericModelConfigObject value: + genericModelConfigObject(value); + break; + case string value: + @string(value); + break; + default: + throw new StagehandInvalidDataException( + "Data did not match any variant of AgentConfigModel" + ); + } + } + + /// + /// Calls the function parameter corresponding to the variant the instance was constructed with and + /// returns its result. + /// + /// Use the TryPick method(s) if you don't need to handle every variant, or + /// if you don't need your function parameters to return a value. + /// + /// + /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data + /// that doesn't match any variant's expected shape). + /// + /// + /// + /// + /// var result = instance.Match( + /// (AgentConfigModelVertexModelConfigObject value) => {...}, + /// (AgentConfigModelAzureEntraModelConfigObject value) => {...}, + /// (AgentConfigModelAzureApiKeyModelConfigObject value) => {...}, + /// (AgentConfigModelGenericModelConfigObject value) => {...}, + /// (string value) => {...} + /// ); + /// + /// + /// + public T Match( + System::Func vertexModelConfigObject, + System::Func azureEntraModelConfigObject, + System::Func azureApiKeyModelConfigObject, + System::Func genericModelConfigObject, + System::Func @string + ) + { + return this.Value switch + { + AgentConfigModelVertexModelConfigObject value => vertexModelConfigObject(value), + AgentConfigModelAzureEntraModelConfigObject value => azureEntraModelConfigObject(value), + AgentConfigModelAzureApiKeyModelConfigObject value => azureApiKeyModelConfigObject( + value + ), + AgentConfigModelGenericModelConfigObject value => genericModelConfigObject(value), + string value => @string(value), + _ => throw new StagehandInvalidDataException( + "Data did not match any variant of AgentConfigModel" + ), + }; + } + + public static implicit operator AgentConfigModel( + AgentConfigModelVertexModelConfigObject value + ) => new(value); + + public static implicit operator AgentConfigModel( + AgentConfigModelAzureEntraModelConfigObject value + ) => new(value); + + public static implicit operator AgentConfigModel( + AgentConfigModelAzureApiKeyModelConfigObject value + ) => new(value); + + public static implicit operator AgentConfigModel( + AgentConfigModelGenericModelConfigObject value + ) => new(value); + + public static implicit operator AgentConfigModel(string value) => new(value); + + /// + /// Validates that the instance was constructed with a known variant and that this variant is valid + /// (based on its own Validate method). + /// + /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). + /// + /// + /// Thrown when the instance does not pass validation. + /// + /// + public override void Validate() + { + if (this.Value == null) + { + throw new StagehandInvalidDataException( + "Data did not match any variant of AgentConfigModel" + ); + } + this.Switch( + (vertexModelConfigObject) => vertexModelConfigObject.Validate(), + (azureEntraModelConfigObject) => azureEntraModelConfigObject.Validate(), + (azureApiKeyModelConfigObject) => azureApiKeyModelConfigObject.Validate(), + (genericModelConfigObject) => genericModelConfigObject.Validate(), + (_) => { } + ); + } + + public virtual bool Equals(AgentConfigModel? other) => + other != null + && this.VariantIndex() == other.VariantIndex() + && JsonElement.DeepEquals(this.Json, other.Json); + + public override int GetHashCode() + { + return 0; + } + + public override string ToString() => + JsonSerializer.Serialize( + FriendlyJsonPrinter.PrintValue(this.Json), + ModelBase.ToStringSerializerOptions + ); + + int VariantIndex() + { + return this.Value switch + { + AgentConfigModelVertexModelConfigObject _ => 0, + AgentConfigModelAzureEntraModelConfigObject _ => 1, + AgentConfigModelAzureApiKeyModelConfigObject _ => 2, + AgentConfigModelGenericModelConfigObject _ => 3, + string _ => 4, + _ => -1, + }; + } +} + +sealed class AgentConfigModelConverter : JsonConverter +{ + public override AgentConfigModel? Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + var element = JsonSerializer.Deserialize(ref reader, options); + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + + try + { + var deserialized = JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + + try + { + var deserialized = JsonSerializer.Deserialize(element, options); + if (deserialized != null) + { + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + + return new(element); + } + + public override void Write( + Utf8JsonWriter writer, + AgentConfigModel value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize(writer, value.Json, options); + } +} + +[JsonConverter( + typeof(JsonModelConverter< + AgentConfigModelVertexModelConfigObject, + AgentConfigModelVertexModelConfigObjectFromRaw + >) +)] +public sealed record class AgentConfigModelVertexModelConfigObject : JsonModel +{ + /// + /// Vertex provider authentication configuration + /// + public required AgentConfigModelVertexModelConfigObjectAuth Auth + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "auth" + ); + } + init { this._rawData.Set("auth", value); } + } + + /// + /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + /// + public required string ModelName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("modelName"); + } + init { this._rawData.Set("modelName", value); } + } + + /// + /// Vertex AI model provider + /// + public JsonElement Provider + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("provider"); + } + init { this._rawData.Set("provider", value); } + } + + /// + /// Vertex provider-specific model configuration + /// + public required AgentConfigModelVertexModelConfigObjectProviderOptions ProviderOptions + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "providerOptions" + ); + } + init { this._rawData.Set("providerOptions", value); } + } + + /// + /// API key for the model provider + /// + public string? ApiKey + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiKey"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiKey", value); + } + } + + /// + /// Base URL for the model provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the model provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + public override void Validate() + { + this.Auth.Validate(); + _ = this.ModelName; + if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("vertex"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + this.ProviderOptions.Validate(); + _ = this.ApiKey; + _ = this.BaseUrl; + _ = this.Headers; + } + + public AgentConfigModelVertexModelConfigObject() + { + this.Provider = JsonSerializer.SerializeToElement("vertex"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public AgentConfigModelVertexModelConfigObject( + AgentConfigModelVertexModelConfigObject agentConfigModelVertexModelConfigObject + ) + : base(agentConfigModelVertexModelConfigObject) { } +#pragma warning restore CS8618 + + public AgentConfigModelVertexModelConfigObject(IReadOnlyDictionary rawData) + { + this._rawData = new(rawData); + + this.Provider = JsonSerializer.SerializeToElement("vertex"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AgentConfigModelVertexModelConfigObject(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static AgentConfigModelVertexModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AgentConfigModelVertexModelConfigObjectFromRaw + : IFromRawJson +{ + /// + public AgentConfigModelVertexModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AgentConfigModelVertexModelConfigObject.FromRawUnchecked(rawData); +} + +/// +/// Vertex provider authentication configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + AgentConfigModelVertexModelConfigObjectAuth, + AgentConfigModelVertexModelConfigObjectAuthFromRaw + >) +)] +public sealed record class AgentConfigModelVertexModelConfigObjectAuth : JsonModel +{ + /// + /// Google Cloud service account credentials + /// + public required AgentConfigModelVertexModelConfigObjectAuthCredentials Credentials + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "credentials" + ); + } + init { this._rawData.Set("credentials", value); } + } + + /// + /// Use inline Google Cloud service account credentials for provider authentication + /// + public JsonElement Type + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("type"); + } + init { this._rawData.Set("type", value); } + } + + /// + /// Google Cloud project ID used by google-auth-library + /// + public string? ProjectID + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("projectId"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("projectId", value); + } + } + + /// + /// Google auth scopes for the desired API request + /// + public AgentConfigModelVertexModelConfigObjectAuthScopes? Scopes + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass( + "scopes" + ); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("scopes", value); + } + } + + /// + /// Google Cloud universe domain + /// + public string? UniverseDomain + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("universeDomain"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("universeDomain", value); + } + } + + /// + public override void Validate() + { + this.Credentials.Validate(); + if ( + !JsonElement.DeepEquals( + this.Type, + JsonSerializer.SerializeToElement("googleServiceAccount") + ) + ) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + _ = this.ProjectID; + this.Scopes?.Validate(); + _ = this.UniverseDomain; + } + + public AgentConfigModelVertexModelConfigObjectAuth() + { + this.Type = JsonSerializer.SerializeToElement("googleServiceAccount"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public AgentConfigModelVertexModelConfigObjectAuth( + AgentConfigModelVertexModelConfigObjectAuth agentConfigModelVertexModelConfigObjectAuth + ) + : base(agentConfigModelVertexModelConfigObjectAuth) { } +#pragma warning restore CS8618 + + public AgentConfigModelVertexModelConfigObjectAuth( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + + this.Type = JsonSerializer.SerializeToElement("googleServiceAccount"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AgentConfigModelVertexModelConfigObjectAuth(FrozenDictionary rawData) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static AgentConfigModelVertexModelConfigObjectAuth FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public AgentConfigModelVertexModelConfigObjectAuth( + AgentConfigModelVertexModelConfigObjectAuthCredentials credentials + ) + : this() + { + this.Credentials = credentials; } +} - public override void Write( - Utf8JsonWriter writer, - ExecutionModelGenericModelConfigObjectProvider value, - JsonSerializerOptions options +class AgentConfigModelVertexModelConfigObjectAuthFromRaw + : IFromRawJson +{ + /// + public AgentConfigModelVertexModelConfigObjectAuth FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AgentConfigModelVertexModelConfigObjectAuth.FromRawUnchecked(rawData); +} + +/// +/// Google Cloud service account credentials +/// +[JsonConverter( + typeof(JsonModelConverter< + AgentConfigModelVertexModelConfigObjectAuthCredentials, + AgentConfigModelVertexModelConfigObjectAuthCredentialsFromRaw + >) +)] +public sealed record class AgentConfigModelVertexModelConfigObjectAuthCredentials : JsonModel +{ + public required string ClientEmail + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("client_email"); + } + init { this._rawData.Set("client_email", value); } + } + + public required string PrivateKey + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("private_key"); + } + init { this._rawData.Set("private_key", value); } + } + + public string? AuthProviderX509CertUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("auth_provider_x509_cert_url"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("auth_provider_x509_cert_url", value); + } + } + + public string? AuthUri + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("auth_uri"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("auth_uri", value); + } + } + + public string? ClientID + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("client_id"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("client_id", value); + } + } + + public string? ClientX509CertUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("client_x509_cert_url"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("client_x509_cert_url", value); + } + } + + public string? PrivateKeyID + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("private_key_id"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("private_key_id", value); + } + } + + public string? ProjectID + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("project_id"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("project_id", value); + } + } + + public string? TokenUri + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("token_uri"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("token_uri", value); + } + } + + public ApiEnum? Type + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass< + ApiEnum + >("type"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("type", value); + } + } + + public string? UniverseDomain + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("universe_domain"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("universe_domain", value); + } + } + + /// + public override void Validate() + { + _ = this.ClientEmail; + _ = this.PrivateKey; + _ = this.AuthProviderX509CertUrl; + _ = this.AuthUri; + _ = this.ClientID; + _ = this.ClientX509CertUrl; + _ = this.PrivateKeyID; + _ = this.ProjectID; + _ = this.TokenUri; + this.Type?.Validate(); + _ = this.UniverseDomain; + } + + public AgentConfigModelVertexModelConfigObjectAuthCredentials() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public AgentConfigModelVertexModelConfigObjectAuthCredentials( + AgentConfigModelVertexModelConfigObjectAuthCredentials agentConfigModelVertexModelConfigObjectAuthCredentials + ) + : base(agentConfigModelVertexModelConfigObjectAuthCredentials) { } +#pragma warning restore CS8618 + + public AgentConfigModelVertexModelConfigObjectAuthCredentials( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AgentConfigModelVertexModelConfigObjectAuthCredentials( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static AgentConfigModelVertexModelConfigObjectAuthCredentials FromRawUnchecked( + IReadOnlyDictionary rawData ) { - JsonSerializer.Serialize( - writer, - value switch - { - ExecutionModelGenericModelConfigObjectProvider.OpenAI => "openai", - ExecutionModelGenericModelConfigObjectProvider.Anthropic => "anthropic", - ExecutionModelGenericModelConfigObjectProvider.Google => "google", - ExecutionModelGenericModelConfigObjectProvider.Microsoft => "microsoft", - ExecutionModelGenericModelConfigObjectProvider.Bedrock => "bedrock", - _ => throw new StagehandInvalidDataException( - string.Format("Invalid value '{0}' in {1}", value, nameof(value)) - ), - }, - options - ); + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } } -/// -/// Tool mode for the agent (dom, hybrid, cua). If set, overrides cua. -/// -[JsonConverter(typeof(ModeConverter))] -public enum Mode +class AgentConfigModelVertexModelConfigObjectAuthCredentialsFromRaw + : IFromRawJson { - Dom, - Hybrid, - Cua, + /// + public AgentConfigModelVertexModelConfigObjectAuthCredentials FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AgentConfigModelVertexModelConfigObjectAuthCredentials.FromRawUnchecked(rawData); } -sealed class ModeConverter : JsonConverter +[JsonConverter(typeof(AgentConfigModelVertexModelConfigObjectAuthCredentialsTypeConverter))] +public enum AgentConfigModelVertexModelConfigObjectAuthCredentialsType { - public override Mode Read( + ServiceAccount, +} + +sealed class AgentConfigModelVertexModelConfigObjectAuthCredentialsTypeConverter + : JsonConverter +{ + public override AgentConfigModelVertexModelConfigObjectAuthCredentialsType Read( ref Utf8JsonReader reader, System::Type typeToConvert, JsonSerializerOptions options @@ -2168,22 +4446,24 @@ JsonSerializerOptions options { return JsonSerializer.Deserialize(ref reader, options) switch { - "dom" => Mode.Dom, - "hybrid" => Mode.Hybrid, - "cua" => Mode.Cua, - _ => (Mode)(-1), + "service_account" => + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, + _ => (AgentConfigModelVertexModelConfigObjectAuthCredentialsType)(-1), }; } - public override void Write(Utf8JsonWriter writer, Mode value, JsonSerializerOptions options) + public override void Write( + Utf8JsonWriter writer, + AgentConfigModelVertexModelConfigObjectAuthCredentialsType value, + JsonSerializerOptions options + ) { JsonSerializer.Serialize( writer, value switch { - Mode.Dom => "dom", - Mode.Hybrid => "hybrid", - Mode.Cua => "cua", + AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount => + "service_account", _ => throw new StagehandInvalidDataException( string.Format("Invalid value '{0}' in {1}", value, nameof(value)) ), @@ -2194,10 +4474,10 @@ public override void Write(Utf8JsonWriter writer, Mode value, JsonSerializerOpti } /// -/// Model configuration object or model name string (e.g., 'openai/gpt-5-nano') +/// Google auth scopes for the desired API request /// -[JsonConverter(typeof(AgentConfigModelConverter))] -public record class AgentConfigModel : ModelBase +[JsonConverter(typeof(AgentConfigModelVertexModelConfigObjectAuthScopesConverter))] +public record class AgentConfigModelVertexModelConfigObjectAuthScopes : ModelBase { public object? Value { get; } = null; @@ -2214,44 +4494,8 @@ public JsonElement Json } } - public string? ModelName - { - get - { - return Match( - vertexModelConfigObject: (x) => x.ModelName, - genericModelConfigObject: (x) => x.ModelName, - @string: (_) => null - ); - } - } - - public string? ApiKey - { - get - { - return Match( - vertexModelConfigObject: (x) => x.ApiKey, - genericModelConfigObject: (x) => x.ApiKey, - @string: (_) => null - ); - } - } - - public string? BaseUrl - { - get - { - return Match( - vertexModelConfigObject: (x) => x.BaseUrl, - genericModelConfigObject: (x) => x.BaseUrl, - @string: (_) => null - ); - } - } - - public AgentConfigModel( - AgentConfigModelVertexModelConfigObject value, + public AgentConfigModelVertexModelConfigObjectAuthScopes( + string value, JsonElement? element = null ) { @@ -2259,90 +4503,59 @@ public AgentConfigModel( this._element = element; } - public AgentConfigModel( - AgentConfigModelGenericModelConfigObject value, + public AgentConfigModelVertexModelConfigObjectAuthScopes( + IReadOnlyList value, JsonElement? element = null ) { - this.Value = value; - this._element = element; - } - - public AgentConfigModel(string value, JsonElement? element = null) - { - this.Value = value; + this.Value = ImmutableArray.ToImmutableArray(value); this._element = element; } - public AgentConfigModel(JsonElement element) + public AgentConfigModelVertexModelConfigObjectAuthScopes(JsonElement element) { this._element = element; } /// /// Returns true and sets the out parameter if the instance was constructed with a variant of - /// type . - /// - /// Consider using or if you need to handle every variant. - /// - /// - /// - /// if (instance.TryPickVertexModelConfigObject(out var value)) { - /// // `value` is of type `AgentConfigModelVertexModelConfigObject` - /// Console.WriteLine(value); - /// } - /// - /// - /// - public bool TryPickVertexModelConfigObject( - [NotNullWhen(true)] out AgentConfigModelVertexModelConfigObject? value - ) - { - value = this.Value as AgentConfigModelVertexModelConfigObject; - return value != null; - } - - /// - /// Returns true and sets the out parameter if the instance was constructed with a variant of - /// type . + /// type . /// /// Consider using or if you need to handle every variant. /// /// /// - /// if (instance.TryPickGenericModelConfigObject(out var value)) { - /// // `value` is of type `AgentConfigModelGenericModelConfigObject` + /// if (instance.TryPickString(out var value)) { + /// // `value` is of type `string` /// Console.WriteLine(value); /// } /// /// /// - public bool TryPickGenericModelConfigObject( - [NotNullWhen(true)] out AgentConfigModelGenericModelConfigObject? value - ) + public bool TryPickString([NotNullWhen(true)] out string? value) { - value = this.Value as AgentConfigModelGenericModelConfigObject; + value = this.Value as string; return value != null; } /// /// Returns true and sets the out parameter if the instance was constructed with a variant of - /// type . + /// type where T is a string. /// /// Consider using or if you need to handle every variant. /// /// /// - /// if (instance.TryPickString(out var value)) { - /// // `value` is of type `string` + /// if (instance.TryPickStrings(out var value)) { + /// // `value` is of type `IReadOnlyList<string>` /// Console.WriteLine(value); /// } /// /// /// - public bool TryPickString([NotNullWhen(true)] out string? value) + public bool TryPickStrings([NotNullWhen(true)] out IReadOnlyList? value) { - value = this.Value as string; + value = this.Value as IReadOnlyList; return value != null; } @@ -2360,33 +4573,28 @@ public bool TryPickString([NotNullWhen(true)] out string? value) /// /// /// instance.Switch( - /// (AgentConfigModelVertexModelConfigObject value) => {...}, - /// (AgentConfigModelGenericModelConfigObject value) => {...}, - /// (string value) => {...} + /// (string value) => {...}, + /// (IReadOnlyList<string> value) => {...} /// ); /// /// /// public void Switch( - System::Action vertexModelConfigObject, - System::Action genericModelConfigObject, - System::Action @string + System::Action @string, + System::Action> strings ) { switch (this.Value) { - case AgentConfigModelVertexModelConfigObject value: - vertexModelConfigObject(value); - break; - case AgentConfigModelGenericModelConfigObject value: - genericModelConfigObject(value); - break; case string value: @string(value); break; + case IReadOnlyList value: + strings(value); + break; default: throw new StagehandInvalidDataException( - "Data did not match any variant of AgentConfigModel" + "Data did not match any variant of AgentConfigModelVertexModelConfigObjectAuthScopes" ); } } @@ -2406,39 +4614,34 @@ public void Switch( /// /// /// var result = instance.Match( - /// (AgentConfigModelVertexModelConfigObject value) => {...}, - /// (AgentConfigModelGenericModelConfigObject value) => {...}, - /// (string value) => {...} + /// (string value) => {...}, + /// (IReadOnlyList<string> value) => {...} /// ); /// /// /// public T Match( - System::Func vertexModelConfigObject, - System::Func genericModelConfigObject, - System::Func @string + System::Func @string, + System::Func, T> strings ) { return this.Value switch { - AgentConfigModelVertexModelConfigObject value => vertexModelConfigObject(value), - AgentConfigModelGenericModelConfigObject value => genericModelConfigObject(value), string value => @string(value), + IReadOnlyList value => strings(value), _ => throw new StagehandInvalidDataException( - "Data did not match any variant of AgentConfigModel" + "Data did not match any variant of AgentConfigModelVertexModelConfigObjectAuthScopes" ), }; } - public static implicit operator AgentConfigModel( - AgentConfigModelVertexModelConfigObject value - ) => new(value); - - public static implicit operator AgentConfigModel( - AgentConfigModelGenericModelConfigObject value + public static implicit operator AgentConfigModelVertexModelConfigObjectAuthScopes( + string value ) => new(value); - public static implicit operator AgentConfigModel(string value) => new(value); + public static implicit operator AgentConfigModelVertexModelConfigObjectAuthScopes( + List value + ) => new((IReadOnlyList)value); /// /// Validates that the instance was constructed with a known variant and that this variant is valid @@ -2455,17 +4658,12 @@ public override void Validate() if (this.Value == null) { throw new StagehandInvalidDataException( - "Data did not match any variant of AgentConfigModel" + "Data did not match any variant of AgentConfigModelVertexModelConfigObjectAuthScopes" ); } - this.Switch( - (vertexModelConfigObject) => vertexModelConfigObject.Validate(), - (genericModelConfigObject) => genericModelConfigObject.Validate(), - (_) => { } - ); } - public virtual bool Equals(AgentConfigModel? other) => + public virtual bool Equals(AgentConfigModelVertexModelConfigObjectAuthScopes? other) => other != null && this.VariantIndex() == other.VariantIndex() && JsonElement.DeepEquals(this.Json, other.Json); @@ -2485,17 +4683,17 @@ int VariantIndex() { return this.Value switch { - AgentConfigModelVertexModelConfigObject _ => 0, - AgentConfigModelGenericModelConfigObject _ => 1, - string _ => 2, + string _ => 0, + IReadOnlyList _ => 1, _ => -1, }; } } -sealed class AgentConfigModelConverter : JsonConverter +sealed class AgentConfigModelVertexModelConfigObjectAuthScopesConverter + : JsonConverter { - public override AgentConfigModel? Read( + public override AgentConfigModelVertexModelConfigObjectAuthScopes? Read( ref Utf8JsonReader reader, System::Type typeToConvert, JsonSerializerOptions options @@ -2504,30 +4702,9 @@ JsonSerializerOptions options var element = JsonSerializer.Deserialize(ref reader, options); try { - var deserialized = JsonSerializer.Deserialize( - element, - options - ); - if (deserialized != null) - { - deserialized.Validate(); - return new(deserialized, element); - } - } - catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) - { - // ignore - } - - try - { - var deserialized = JsonSerializer.Deserialize( - element, - options - ); + var deserialized = JsonSerializer.Deserialize(element, options); if (deserialized != null) { - deserialized.Validate(); return new(deserialized, element); } } @@ -2538,7 +4715,7 @@ JsonSerializerOptions options try { - var deserialized = JsonSerializer.Deserialize(element, options); + var deserialized = JsonSerializer.Deserialize>(element, options); if (deserialized != null) { return new(deserialized, element); @@ -2554,7 +4731,7 @@ JsonSerializerOptions options public override void Write( Utf8JsonWriter writer, - AgentConfigModel value, + AgentConfigModelVertexModelConfigObjectAuthScopes value, JsonSerializerOptions options ) { @@ -2562,79 +4739,159 @@ JsonSerializerOptions options } } +/// +/// Vertex provider-specific model configuration +/// [JsonConverter( typeof(JsonModelConverter< - AgentConfigModelVertexModelConfigObject, - AgentConfigModelVertexModelConfigObjectFromRaw + AgentConfigModelVertexModelConfigObjectProviderOptions, + AgentConfigModelVertexModelConfigObjectProviderOptionsFromRaw >) )] -public sealed record class AgentConfigModelVertexModelConfigObject : JsonModel +public sealed record class AgentConfigModelVertexModelConfigObjectProviderOptions : JsonModel { /// - /// Vertex provider authentication configuration + /// Vertex AI provider-specific settings /// - public required AgentConfigModelVertexModelConfigObjectAuth Auth + public required AgentConfigModelVertexModelConfigObjectProviderOptionsVertex Vertex { get { this._rawData.Freeze(); - return this._rawData.GetNotNullClass( - "auth" + return this._rawData.GetNotNullClass( + "vertex" ); } - init { this._rawData.Set("auth", value); } + init { this._rawData.Set("vertex", value); } + } + + /// + public override void Validate() + { + this.Vertex.Validate(); + } + + public AgentConfigModelVertexModelConfigObjectProviderOptions() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public AgentConfigModelVertexModelConfigObjectProviderOptions( + AgentConfigModelVertexModelConfigObjectProviderOptions agentConfigModelVertexModelConfigObjectProviderOptions + ) + : base(agentConfigModelVertexModelConfigObjectProviderOptions) { } +#pragma warning restore CS8618 + + public AgentConfigModelVertexModelConfigObjectProviderOptions( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AgentConfigModelVertexModelConfigObjectProviderOptions( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static AgentConfigModelVertexModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); } + [SetsRequiredMembers] + public AgentConfigModelVertexModelConfigObjectProviderOptions( + AgentConfigModelVertexModelConfigObjectProviderOptionsVertex vertex + ) + : this() + { + this.Vertex = vertex; + } +} + +class AgentConfigModelVertexModelConfigObjectProviderOptionsFromRaw + : IFromRawJson +{ + /// + public AgentConfigModelVertexModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AgentConfigModelVertexModelConfigObjectProviderOptions.FromRawUnchecked(rawData); +} + +/// +/// Vertex AI provider-specific settings +/// +[JsonConverter( + typeof(JsonModelConverter< + AgentConfigModelVertexModelConfigObjectProviderOptionsVertex, + AgentConfigModelVertexModelConfigObjectProviderOptionsVertexFromRaw + >) +)] +public sealed record class AgentConfigModelVertexModelConfigObjectProviderOptionsVertex : JsonModel +{ /// - /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + /// Google Cloud location for Vertex AI models /// - public required string ModelName + public required string Location { get { this._rawData.Freeze(); - return this._rawData.GetNotNullClass("modelName"); + return this._rawData.GetNotNullClass("location"); } - init { this._rawData.Set("modelName", value); } + init { this._rawData.Set("location", value); } } /// - /// Vertex AI model provider + /// Google Cloud project ID for Vertex AI models /// - public JsonElement Provider + public required string Project { get { this._rawData.Freeze(); - return this._rawData.GetNotNullStruct("provider"); + return this._rawData.GetNotNullClass("project"); } - init { this._rawData.Set("provider", value); } + init { this._rawData.Set("project", value); } } /// - /// Vertex provider-specific model configuration + /// Base URL for the Vertex AI provider /// - public required AgentConfigModelVertexModelConfigObjectProviderOptions ProviderOptions + public string? BaseUrl { get { this._rawData.Freeze(); - return this._rawData.GetNotNullClass( - "providerOptions" - ); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); } - init { this._rawData.Set("providerOptions", value); } } /// - /// API key for the model provider + /// Custom headers sent with every request to the Vertex AI provider /// - public string? ApiKey + public IReadOnlyDictionary? Headers { get { this._rawData.Freeze(); - return this._rawData.GetNullableClass("apiKey"); + return this._rawData.GetNullableClass>("headers"); } init { @@ -2643,8 +4900,129 @@ public string? ApiKey return; } - this._rawData.Set("apiKey", value); + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + public override void Validate() + { + _ = this.Location; + _ = this.Project; + _ = this.BaseUrl; + _ = this.Headers; + } + + public AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public AgentConfigModelVertexModelConfigObjectProviderOptionsVertex( + AgentConfigModelVertexModelConfigObjectProviderOptionsVertex agentConfigModelVertexModelConfigObjectProviderOptionsVertex + ) + : base(agentConfigModelVertexModelConfigObjectProviderOptionsVertex) { } +#pragma warning restore CS8618 + + public AgentConfigModelVertexModelConfigObjectProviderOptionsVertex( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AgentConfigModelVertexModelConfigObjectProviderOptionsVertex( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static AgentConfigModelVertexModelConfigObjectProviderOptionsVertex FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AgentConfigModelVertexModelConfigObjectProviderOptionsVertexFromRaw + : IFromRawJson +{ + /// + public AgentConfigModelVertexModelConfigObjectProviderOptionsVertex FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AgentConfigModelVertexModelConfigObjectProviderOptionsVertex.FromRawUnchecked(rawData); +} + +[JsonConverter( + typeof(JsonModelConverter< + AgentConfigModelAzureEntraModelConfigObject, + AgentConfigModelAzureEntraModelConfigObjectFromRaw + >) +)] +public sealed record class AgentConfigModelAzureEntraModelConfigObject : JsonModel +{ + /// + /// Azure provider authentication configuration + /// + public required AgentConfigModelAzureEntraModelConfigObjectAuth Auth + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "auth" + ); + } + init { this._rawData.Set("auth", value); } + } + + /// + /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + /// + public required string ModelName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("modelName"); + } + init { this._rawData.Set("modelName", value); } + } + + /// + /// Azure OpenAI model provider + /// + public JsonElement Provider + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("provider"); + } + init { this._rawData.Set("provider", value); } + } + + /// + /// Azure provider-specific model configuration + /// + public required AgentConfigModelAzureEntraModelConfigObjectProviderOptions ProviderOptions + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "providerOptions" + ); } + init { this._rawData.Set("providerOptions", value); } } /// @@ -2697,46 +5075,47 @@ public override void Validate() { this.Auth.Validate(); _ = this.ModelName; - if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("vertex"))) + if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("azure"))) { throw new StagehandInvalidDataException("Invalid value given for constant"); } this.ProviderOptions.Validate(); - _ = this.ApiKey; _ = this.BaseUrl; _ = this.Headers; } - public AgentConfigModelVertexModelConfigObject() + public AgentConfigModelAzureEntraModelConfigObject() { - this.Provider = JsonSerializer.SerializeToElement("vertex"); + this.Provider = JsonSerializer.SerializeToElement("azure"); } #pragma warning disable CS8618 [SetsRequiredMembers] - public AgentConfigModelVertexModelConfigObject( - AgentConfigModelVertexModelConfigObject agentConfigModelVertexModelConfigObject + public AgentConfigModelAzureEntraModelConfigObject( + AgentConfigModelAzureEntraModelConfigObject agentConfigModelAzureEntraModelConfigObject ) - : base(agentConfigModelVertexModelConfigObject) { } + : base(agentConfigModelAzureEntraModelConfigObject) { } #pragma warning restore CS8618 - public AgentConfigModelVertexModelConfigObject(IReadOnlyDictionary rawData) + public AgentConfigModelAzureEntraModelConfigObject( + IReadOnlyDictionary rawData + ) { this._rawData = new(rawData); - this.Provider = JsonSerializer.SerializeToElement("vertex"); + this.Provider = JsonSerializer.SerializeToElement("azure"); } #pragma warning disable CS8618 [SetsRequiredMembers] - AgentConfigModelVertexModelConfigObject(FrozenDictionary rawData) + AgentConfigModelAzureEntraModelConfigObject(FrozenDictionary rawData) { this._rawData = new(rawData); } #pragma warning restore CS8618 - /// - public static AgentConfigModelVertexModelConfigObject FromRawUnchecked( + /// + public static AgentConfigModelAzureEntraModelConfigObject FromRawUnchecked( IReadOnlyDictionary rawData ) { @@ -2744,43 +5123,41 @@ IReadOnlyDictionary rawData } } -class AgentConfigModelVertexModelConfigObjectFromRaw - : IFromRawJson +class AgentConfigModelAzureEntraModelConfigObjectFromRaw + : IFromRawJson { /// - public AgentConfigModelVertexModelConfigObject FromRawUnchecked( + public AgentConfigModelAzureEntraModelConfigObject FromRawUnchecked( IReadOnlyDictionary rawData - ) => AgentConfigModelVertexModelConfigObject.FromRawUnchecked(rawData); + ) => AgentConfigModelAzureEntraModelConfigObject.FromRawUnchecked(rawData); } /// -/// Vertex provider authentication configuration +/// Azure provider authentication configuration /// [JsonConverter( typeof(JsonModelConverter< - AgentConfigModelVertexModelConfigObjectAuth, - AgentConfigModelVertexModelConfigObjectAuthFromRaw + AgentConfigModelAzureEntraModelConfigObjectAuth, + AgentConfigModelAzureEntraModelConfigObjectAuthFromRaw >) )] -public sealed record class AgentConfigModelVertexModelConfigObjectAuth : JsonModel +public sealed record class AgentConfigModelAzureEntraModelConfigObjectAuth : JsonModel { /// - /// Google Cloud service account credentials + /// Microsoft Entra ID bearer token for Azure OpenAI /// - public required AgentConfigModelVertexModelConfigObjectAuthCredentials Credentials + public required string Token { get { this._rawData.Freeze(); - return this._rawData.GetNotNullClass( - "credentials" - ); + return this._rawData.GetNotNullClass("token"); } - init { this._rawData.Set("credentials", value); } + init { this._rawData.Set("token", value); } } /// - /// Use inline Google Cloud service account credentials for provider authentication + /// Use a Microsoft Entra ID bearer token for authentication /// public JsonElement Type { @@ -2792,121 +5169,48 @@ public JsonElement Type init { this._rawData.Set("type", value); } } - /// - /// Google Cloud project ID used by google-auth-library - /// - public string? ProjectID - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("projectId"); - } - init - { - if (value == null) - { - return; - } - - this._rawData.Set("projectId", value); - } - } - - /// - /// Google auth scopes for the desired API request - /// - public AgentConfigModelVertexModelConfigObjectAuthScopes? Scopes - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass( - "scopes" - ); - } - init - { - if (value == null) - { - return; - } - - this._rawData.Set("scopes", value); - } - } - - /// - /// Google Cloud universe domain - /// - public string? UniverseDomain - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("universeDomain"); - } - init - { - if (value == null) - { - return; - } - - this._rawData.Set("universeDomain", value); - } - } - /// public override void Validate() { - this.Credentials.Validate(); - if ( - !JsonElement.DeepEquals( - this.Type, - JsonSerializer.SerializeToElement("googleServiceAccount") - ) - ) + _ = this.Token; + if (!JsonElement.DeepEquals(this.Type, JsonSerializer.SerializeToElement("azureEntraId"))) { throw new StagehandInvalidDataException("Invalid value given for constant"); } - _ = this.ProjectID; - this.Scopes?.Validate(); - _ = this.UniverseDomain; } - public AgentConfigModelVertexModelConfigObjectAuth() + public AgentConfigModelAzureEntraModelConfigObjectAuth() { - this.Type = JsonSerializer.SerializeToElement("googleServiceAccount"); + this.Type = JsonSerializer.SerializeToElement("azureEntraId"); } #pragma warning disable CS8618 [SetsRequiredMembers] - public AgentConfigModelVertexModelConfigObjectAuth( - AgentConfigModelVertexModelConfigObjectAuth agentConfigModelVertexModelConfigObjectAuth + public AgentConfigModelAzureEntraModelConfigObjectAuth( + AgentConfigModelAzureEntraModelConfigObjectAuth agentConfigModelAzureEntraModelConfigObjectAuth ) - : base(agentConfigModelVertexModelConfigObjectAuth) { } + : base(agentConfigModelAzureEntraModelConfigObjectAuth) { } #pragma warning restore CS8618 - public AgentConfigModelVertexModelConfigObjectAuth( + public AgentConfigModelAzureEntraModelConfigObjectAuth( IReadOnlyDictionary rawData ) { this._rawData = new(rawData); - this.Type = JsonSerializer.SerializeToElement("googleServiceAccount"); + this.Type = JsonSerializer.SerializeToElement("azureEntraId"); } #pragma warning disable CS8618 [SetsRequiredMembers] - AgentConfigModelVertexModelConfigObjectAuth(FrozenDictionary rawData) + AgentConfigModelAzureEntraModelConfigObjectAuth(FrozenDictionary rawData) { this._rawData = new(rawData); } #pragma warning restore CS8618 - /// - public static AgentConfigModelVertexModelConfigObjectAuth FromRawUnchecked( + /// + public static AgentConfigModelAzureEntraModelConfigObjectAuth FromRawUnchecked( IReadOnlyDictionary rawData ) { @@ -2914,133 +5218,129 @@ IReadOnlyDictionary rawData } [SetsRequiredMembers] - public AgentConfigModelVertexModelConfigObjectAuth( - AgentConfigModelVertexModelConfigObjectAuthCredentials credentials - ) + public AgentConfigModelAzureEntraModelConfigObjectAuth(string token) : this() { - this.Credentials = credentials; + this.Token = token; } } -class AgentConfigModelVertexModelConfigObjectAuthFromRaw - : IFromRawJson +class AgentConfigModelAzureEntraModelConfigObjectAuthFromRaw + : IFromRawJson { /// - public AgentConfigModelVertexModelConfigObjectAuth FromRawUnchecked( + public AgentConfigModelAzureEntraModelConfigObjectAuth FromRawUnchecked( IReadOnlyDictionary rawData - ) => AgentConfigModelVertexModelConfigObjectAuth.FromRawUnchecked(rawData); + ) => AgentConfigModelAzureEntraModelConfigObjectAuth.FromRawUnchecked(rawData); } /// -/// Google Cloud service account credentials +/// Azure provider-specific model configuration /// [JsonConverter( typeof(JsonModelConverter< - AgentConfigModelVertexModelConfigObjectAuthCredentials, - AgentConfigModelVertexModelConfigObjectAuthCredentialsFromRaw + AgentConfigModelAzureEntraModelConfigObjectProviderOptions, + AgentConfigModelAzureEntraModelConfigObjectProviderOptionsFromRaw >) )] -public sealed record class AgentConfigModelVertexModelConfigObjectAuthCredentials : JsonModel +public sealed record class AgentConfigModelAzureEntraModelConfigObjectProviderOptions : JsonModel { - public required string ClientEmail + /// + /// Azure OpenAI provider-specific settings + /// + public required AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure Azure { get { this._rawData.Freeze(); - return this._rawData.GetNotNullClass("client_email"); + return this._rawData.GetNotNullClass( + "azure" + ); } - init { this._rawData.Set("client_email", value); } + init { this._rawData.Set("azure", value); } } - public required string PrivateKey + /// + public override void Validate() { - get - { - this._rawData.Freeze(); - return this._rawData.GetNotNullClass("private_key"); - } - init { this._rawData.Set("private_key", value); } + this.Azure.Validate(); } - public string? AuthProviderX509CertUrl - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("auth_provider_x509_cert_url"); - } - init - { - if (value == null) - { - return; - } + public AgentConfigModelAzureEntraModelConfigObjectProviderOptions() { } - this._rawData.Set("auth_provider_x509_cert_url", value); - } - } +#pragma warning disable CS8618 + [SetsRequiredMembers] + public AgentConfigModelAzureEntraModelConfigObjectProviderOptions( + AgentConfigModelAzureEntraModelConfigObjectProviderOptions agentConfigModelAzureEntraModelConfigObjectProviderOptions + ) + : base(agentConfigModelAzureEntraModelConfigObjectProviderOptions) { } +#pragma warning restore CS8618 - public string? AuthUri + public AgentConfigModelAzureEntraModelConfigObjectProviderOptions( + IReadOnlyDictionary rawData + ) { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("auth_uri"); - } - init - { - if (value == null) - { - return; - } - - this._rawData.Set("auth_uri", value); - } + this._rawData = new(rawData); } - public string? ClientID +#pragma warning disable CS8618 + [SetsRequiredMembers] + AgentConfigModelAzureEntraModelConfigObjectProviderOptions( + FrozenDictionary rawData + ) { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("client_id"); - } - init - { - if (value == null) - { - return; - } - - this._rawData.Set("client_id", value); - } + this._rawData = new(rawData); } +#pragma warning restore CS8618 - public string? ClientX509CertUrl + /// + public static AgentConfigModelAzureEntraModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("client_x509_cert_url"); - } - init - { - if (value == null) - { - return; - } + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } - this._rawData.Set("client_x509_cert_url", value); - } + [SetsRequiredMembers] + public AgentConfigModelAzureEntraModelConfigObjectProviderOptions( + AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure azure + ) + : this() + { + this.Azure = azure; } +} - public string? PrivateKeyID +class AgentConfigModelAzureEntraModelConfigObjectProviderOptionsFromRaw + : IFromRawJson +{ + /// + public AgentConfigModelAzureEntraModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AgentConfigModelAzureEntraModelConfigObjectProviderOptions.FromRawUnchecked(rawData); +} + +/// +/// Azure OpenAI provider-specific settings +/// +[JsonConverter( + typeof(JsonModelConverter< + AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure, + AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzureFromRaw + >) +)] +public sealed record class AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure + : JsonModel +{ + /// + /// Azure OpenAI API version + /// + public string? ApiVersion { get { this._rawData.Freeze(); - return this._rawData.GetNullableClass("private_key_id"); + return this._rawData.GetNullableClass("apiVersion"); } init { @@ -3049,16 +5349,19 @@ public string? PrivateKeyID return; } - this._rawData.Set("private_key_id", value); + this._rawData.Set("apiVersion", value); } } - public string? ProjectID + /// + /// Base URL for the Azure OpenAI provider + /// + public string? BaseUrl { get { this._rawData.Freeze(); - return this._rawData.GetNullableClass("project_id"); + return this._rawData.GetNullableClass("baseURL"); } init { @@ -3067,16 +5370,19 @@ public string? ProjectID return; } - this._rawData.Set("project_id", value); + this._rawData.Set("baseURL", value); } } - public string? TokenUri + /// + /// Custom headers sent with every request to the Azure OpenAI provider + /// + public IReadOnlyDictionary? Headers { get { this._rawData.Freeze(); - return this._rawData.GetNullableClass("token_uri"); + return this._rawData.GetNullableClass>("headers"); } init { @@ -3085,18 +5391,22 @@ public string? TokenUri return; } - this._rawData.Set("token_uri", value); + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); } } - public ApiEnum? Type + /// + /// Azure OpenAI resource name + /// + public string? ResourceName { get { this._rawData.Freeze(); - return this._rawData.GetNullableClass< - ApiEnum - >("type"); + return this._rawData.GetNullableClass("resourceName"); } init { @@ -3105,16 +5415,19 @@ public ApiEnum + /// Whether to use deployment-based Azure OpenAI URLs + /// + public bool? UseDeploymentBasedUrls { get { this._rawData.Freeze(); - return this._rawData.GetNullableClass("universe_domain"); + return this._rawData.GetNullableStruct("useDeploymentBasedUrls"); } init { @@ -3123,37 +5436,31 @@ public string? UniverseDomain return; } - this._rawData.Set("universe_domain", value); + this._rawData.Set("useDeploymentBasedUrls", value); } } /// public override void Validate() { - _ = this.ClientEmail; - _ = this.PrivateKey; - _ = this.AuthProviderX509CertUrl; - _ = this.AuthUri; - _ = this.ClientID; - _ = this.ClientX509CertUrl; - _ = this.PrivateKeyID; - _ = this.ProjectID; - _ = this.TokenUri; - this.Type?.Validate(); - _ = this.UniverseDomain; + _ = this.ApiVersion; + _ = this.BaseUrl; + _ = this.Headers; + _ = this.ResourceName; + _ = this.UseDeploymentBasedUrls; } - public AgentConfigModelVertexModelConfigObjectAuthCredentials() { } + public AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure() { } #pragma warning disable CS8618 [SetsRequiredMembers] - public AgentConfigModelVertexModelConfigObjectAuthCredentials( - AgentConfigModelVertexModelConfigObjectAuthCredentials agentConfigModelVertexModelConfigObjectAuthCredentials + public AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure( + AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure agentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure ) - : base(agentConfigModelVertexModelConfigObjectAuthCredentials) { } + : base(agentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure) { } #pragma warning restore CS8618 - public AgentConfigModelVertexModelConfigObjectAuthCredentials( + public AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure( IReadOnlyDictionary rawData ) { @@ -3162,7 +5469,7 @@ IReadOnlyDictionary rawData #pragma warning disable CS8618 [SetsRequiredMembers] - AgentConfigModelVertexModelConfigObjectAuthCredentials( + AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure( FrozenDictionary rawData ) { @@ -3170,8 +5477,8 @@ FrozenDictionary rawData } #pragma warning restore CS8618 - /// - public static AgentConfigModelVertexModelConfigObjectAuthCredentials FromRawUnchecked( + /// + public static AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure FromRawUnchecked( IReadOnlyDictionary rawData ) { @@ -3179,368 +5486,235 @@ IReadOnlyDictionary rawData } } -class AgentConfigModelVertexModelConfigObjectAuthCredentialsFromRaw - : IFromRawJson +class AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzureFromRaw + : IFromRawJson { /// - public AgentConfigModelVertexModelConfigObjectAuthCredentials FromRawUnchecked( + public AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure FromRawUnchecked( IReadOnlyDictionary rawData - ) => AgentConfigModelVertexModelConfigObjectAuthCredentials.FromRawUnchecked(rawData); -} - -[JsonConverter(typeof(AgentConfigModelVertexModelConfigObjectAuthCredentialsTypeConverter))] -public enum AgentConfigModelVertexModelConfigObjectAuthCredentialsType -{ - ServiceAccount, -} - -sealed class AgentConfigModelVertexModelConfigObjectAuthCredentialsTypeConverter - : JsonConverter -{ - public override AgentConfigModelVertexModelConfigObjectAuthCredentialsType Read( - ref Utf8JsonReader reader, - System::Type typeToConvert, - JsonSerializerOptions options - ) - { - return JsonSerializer.Deserialize(ref reader, options) switch - { - "service_account" => - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount, - _ => (AgentConfigModelVertexModelConfigObjectAuthCredentialsType)(-1), - }; - } - - public override void Write( - Utf8JsonWriter writer, - AgentConfigModelVertexModelConfigObjectAuthCredentialsType value, - JsonSerializerOptions options - ) - { - JsonSerializer.Serialize( - writer, - value switch - { - AgentConfigModelVertexModelConfigObjectAuthCredentialsType.ServiceAccount => - "service_account", - _ => throw new StagehandInvalidDataException( - string.Format("Invalid value '{0}' in {1}", value, nameof(value)) - ), - }, - options - ); - } + ) => AgentConfigModelAzureEntraModelConfigObjectProviderOptionsAzure.FromRawUnchecked(rawData); } -/// -/// Google auth scopes for the desired API request -/// -[JsonConverter(typeof(AgentConfigModelVertexModelConfigObjectAuthScopesConverter))] -public record class AgentConfigModelVertexModelConfigObjectAuthScopes : ModelBase +[JsonConverter( + typeof(JsonModelConverter< + AgentConfigModelAzureApiKeyModelConfigObject, + AgentConfigModelAzureApiKeyModelConfigObjectFromRaw + >) +)] +public sealed record class AgentConfigModelAzureApiKeyModelConfigObject : JsonModel { - public object? Value { get; } = null; - - JsonElement? _element = null; - - public JsonElement Json - { - get - { - return this._element ??= JsonSerializer.SerializeToElement( - this.Value, - ModelBase.SerializerOptions - ); - } - } - - public AgentConfigModelVertexModelConfigObjectAuthScopes( - string value, - JsonElement? element = null - ) - { - this.Value = value; - this._element = element; - } - - public AgentConfigModelVertexModelConfigObjectAuthScopes( - IReadOnlyList value, - JsonElement? element = null - ) - { - this.Value = ImmutableArray.ToImmutableArray(value); - this._element = element; - } - - public AgentConfigModelVertexModelConfigObjectAuthScopes(JsonElement element) - { - this._element = element; - } - - /// - /// Returns true and sets the out parameter if the instance was constructed with a variant of - /// type . - /// - /// Consider using or if you need to handle every variant. - /// - /// - /// - /// if (instance.TryPickString(out var value)) { - /// // `value` is of type `string` - /// Console.WriteLine(value); - /// } - /// - /// - /// - public bool TryPickString([NotNullWhen(true)] out string? value) - { - value = this.Value as string; - return value != null; - } - - /// - /// Returns true and sets the out parameter if the instance was constructed with a variant of - /// type where T is a string. - /// - /// Consider using or if you need to handle every variant. - /// - /// - /// - /// if (instance.TryPickStrings(out var value)) { - /// // `value` is of type `IReadOnlyList<string>` - /// Console.WriteLine(value); - /// } - /// - /// - /// - public bool TryPickStrings([NotNullWhen(true)] out IReadOnlyList? value) - { - value = this.Value as IReadOnlyList; - return value != null; - } - /// - /// Calls the function parameter corresponding to the variant the instance was constructed with. - /// - /// Use the TryPick method(s) if you don't need to handle every variant, or - /// if you need your function parameters to return something. - /// - /// - /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data - /// that doesn't match any variant's expected shape). - /// - /// - /// - /// - /// instance.Switch( - /// (string value) => {...}, - /// (IReadOnlyList<string> value) => {...} - /// ); - /// - /// + /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') /// - public void Switch( - System::Action @string, - System::Action> strings - ) + public required string ModelName { - switch (this.Value) + get { - case string value: - @string(value); - break; - case IReadOnlyList value: - strings(value); - break; - default: - throw new StagehandInvalidDataException( - "Data did not match any variant of AgentConfigModelVertexModelConfigObjectAuthScopes" - ); + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("modelName"); } + init { this._rawData.Set("modelName", value); } } - /// - /// Calls the function parameter corresponding to the variant the instance was constructed with and - /// returns its result. - /// - /// Use the TryPick method(s) if you don't need to handle every variant, or - /// if you don't need your function parameters to return a value. - /// - /// - /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data - /// that doesn't match any variant's expected shape). - /// - /// - /// - /// - /// var result = instance.Match( - /// (string value) => {...}, - /// (IReadOnlyList<string> value) => {...} - /// ); - /// - /// - /// - public T Match( - System::Func @string, - System::Func, T> strings - ) - { - return this.Value switch - { - string value => @string(value), - IReadOnlyList value => strings(value), - _ => throw new StagehandInvalidDataException( - "Data did not match any variant of AgentConfigModelVertexModelConfigObjectAuthScopes" - ), - }; - } - - public static implicit operator AgentConfigModelVertexModelConfigObjectAuthScopes( - string value - ) => new(value); - - public static implicit operator AgentConfigModelVertexModelConfigObjectAuthScopes( - List value - ) => new((IReadOnlyList)value); - - /// - /// Validates that the instance was constructed with a known variant and that this variant is valid - /// (based on its own Validate method). - /// - /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). - /// - /// - /// Thrown when the instance does not pass validation. - /// + /// + /// Azure OpenAI model provider /// - public override void Validate() + public JsonElement Provider { - if (this.Value == null) + get { - throw new StagehandInvalidDataException( - "Data did not match any variant of AgentConfigModelVertexModelConfigObjectAuthScopes" - ); + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("provider"); } + init { this._rawData.Set("provider", value); } } - public virtual bool Equals(AgentConfigModelVertexModelConfigObjectAuthScopes? other) => - other != null - && this.VariantIndex() == other.VariantIndex() - && JsonElement.DeepEquals(this.Json, other.Json); - - public override int GetHashCode() + /// + /// Azure provider-specific model configuration + /// + public required AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions ProviderOptions { - return 0; + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "providerOptions" + ); + } + init { this._rawData.Set("providerOptions", value); } } - public override string ToString() => - JsonSerializer.Serialize( - FriendlyJsonPrinter.PrintValue(this.Json), - ModelBase.ToStringSerializerOptions - ); - - int VariantIndex() + /// + /// API key for the model provider + /// + public string? ApiKey { - return this.Value switch + get { - string _ => 0, - IReadOnlyList _ => 1, - _ => -1, - }; + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiKey"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiKey", value); + } } -} -sealed class AgentConfigModelVertexModelConfigObjectAuthScopesConverter - : JsonConverter -{ - public override AgentConfigModelVertexModelConfigObjectAuthScopes? Read( - ref Utf8JsonReader reader, - System::Type typeToConvert, - JsonSerializerOptions options - ) + /// + /// Base URL for the model provider + /// + public string? BaseUrl { - var element = JsonSerializer.Deserialize(ref reader, options); - try + get { - var deserialized = JsonSerializer.Deserialize(element, options); - if (deserialized != null) + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) { - return new(deserialized, element); + return; } + + this._rawData.Set("baseURL", value); } - catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + } + + /// + /// Custom headers sent with every request to the model provider + /// + public IReadOnlyDictionary? Headers + { + get { - // ignore + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); } - - try + init { - var deserialized = JsonSerializer.Deserialize>(element, options); - if (deserialized != null) + if (value == null) { - return new(deserialized, element); + return; } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); } - catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + } + + /// + public override void Validate() + { + _ = this.ModelName; + if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("azure"))) { - // ignore + throw new StagehandInvalidDataException("Invalid value given for constant"); } + this.ProviderOptions.Validate(); + _ = this.ApiKey; + _ = this.BaseUrl; + _ = this.Headers; + } - return new(element); + public AgentConfigModelAzureApiKeyModelConfigObject() + { + this.Provider = JsonSerializer.SerializeToElement("azure"); } - public override void Write( - Utf8JsonWriter writer, - AgentConfigModelVertexModelConfigObjectAuthScopes value, - JsonSerializerOptions options +#pragma warning disable CS8618 + [SetsRequiredMembers] + public AgentConfigModelAzureApiKeyModelConfigObject( + AgentConfigModelAzureApiKeyModelConfigObject agentConfigModelAzureApiKeyModelConfigObject + ) + : base(agentConfigModelAzureApiKeyModelConfigObject) { } +#pragma warning restore CS8618 + + public AgentConfigModelAzureApiKeyModelConfigObject( + IReadOnlyDictionary rawData ) { - JsonSerializer.Serialize(writer, value.Json, options); + this._rawData = new(rawData); + + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + AgentConfigModelAzureApiKeyModelConfigObject(FrozenDictionary rawData) + { + this._rawData = new(rawData); } +#pragma warning restore CS8618 + + /// + public static AgentConfigModelAzureApiKeyModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class AgentConfigModelAzureApiKeyModelConfigObjectFromRaw + : IFromRawJson +{ + /// + public AgentConfigModelAzureApiKeyModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) => AgentConfigModelAzureApiKeyModelConfigObject.FromRawUnchecked(rawData); } /// -/// Vertex provider-specific model configuration +/// Azure provider-specific model configuration /// [JsonConverter( typeof(JsonModelConverter< - AgentConfigModelVertexModelConfigObjectProviderOptions, - AgentConfigModelVertexModelConfigObjectProviderOptionsFromRaw + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions, + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsFromRaw >) )] -public sealed record class AgentConfigModelVertexModelConfigObjectProviderOptions : JsonModel +public sealed record class AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions : JsonModel { /// - /// Vertex AI provider-specific settings + /// Azure OpenAI provider-specific settings /// - public required AgentConfigModelVertexModelConfigObjectProviderOptionsVertex Vertex + public required AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure Azure { get { this._rawData.Freeze(); - return this._rawData.GetNotNullClass( - "vertex" + return this._rawData.GetNotNullClass( + "azure" ); } - init { this._rawData.Set("vertex", value); } + init { this._rawData.Set("azure", value); } } /// public override void Validate() { - this.Vertex.Validate(); + this.Azure.Validate(); } - public AgentConfigModelVertexModelConfigObjectProviderOptions() { } + public AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions() { } #pragma warning disable CS8618 [SetsRequiredMembers] - public AgentConfigModelVertexModelConfigObjectProviderOptions( - AgentConfigModelVertexModelConfigObjectProviderOptions agentConfigModelVertexModelConfigObjectProviderOptions + public AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions( + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions agentConfigModelAzureApiKeyModelConfigObjectProviderOptions ) - : base(agentConfigModelVertexModelConfigObjectProviderOptions) { } + : base(agentConfigModelAzureApiKeyModelConfigObjectProviderOptions) { } #pragma warning restore CS8618 - public AgentConfigModelVertexModelConfigObjectProviderOptions( + public AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions( IReadOnlyDictionary rawData ) { @@ -3549,7 +5723,7 @@ IReadOnlyDictionary rawData #pragma warning disable CS8618 [SetsRequiredMembers] - AgentConfigModelVertexModelConfigObjectProviderOptions( + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions( FrozenDictionary rawData ) { @@ -3557,8 +5731,8 @@ FrozenDictionary rawData } #pragma warning restore CS8618 - /// - public static AgentConfigModelVertexModelConfigObjectProviderOptions FromRawUnchecked( + /// + public static AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions FromRawUnchecked( IReadOnlyDictionary rawData ) { @@ -3566,63 +5740,59 @@ IReadOnlyDictionary rawData } [SetsRequiredMembers] - public AgentConfigModelVertexModelConfigObjectProviderOptions( - AgentConfigModelVertexModelConfigObjectProviderOptionsVertex vertex + public AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions( + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure azure ) : this() { - this.Vertex = vertex; + this.Azure = azure; } } -class AgentConfigModelVertexModelConfigObjectProviderOptionsFromRaw - : IFromRawJson +class AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsFromRaw + : IFromRawJson { /// - public AgentConfigModelVertexModelConfigObjectProviderOptions FromRawUnchecked( + public AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions FromRawUnchecked( IReadOnlyDictionary rawData - ) => AgentConfigModelVertexModelConfigObjectProviderOptions.FromRawUnchecked(rawData); + ) => AgentConfigModelAzureApiKeyModelConfigObjectProviderOptions.FromRawUnchecked(rawData); } /// -/// Vertex AI provider-specific settings +/// Azure OpenAI provider-specific settings /// [JsonConverter( typeof(JsonModelConverter< - AgentConfigModelVertexModelConfigObjectProviderOptionsVertex, - AgentConfigModelVertexModelConfigObjectProviderOptionsVertexFromRaw + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure, + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzureFromRaw >) )] -public sealed record class AgentConfigModelVertexModelConfigObjectProviderOptionsVertex : JsonModel +public sealed record class AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure + : JsonModel { /// - /// Google Cloud location for Vertex AI models + /// Azure OpenAI API version /// - public required string Location + public string? ApiVersion { get { this._rawData.Freeze(); - return this._rawData.GetNotNullClass("location"); + return this._rawData.GetNullableClass("apiVersion"); } - init { this._rawData.Set("location", value); } - } - - /// - /// Google Cloud project ID for Vertex AI models - /// - public required string Project - { - get + init { - this._rawData.Freeze(); - return this._rawData.GetNotNullClass("project"); + if (value == null) + { + return; + } + + this._rawData.Set("apiVersion", value); } - init { this._rawData.Set("project", value); } } /// - /// Base URL for the Vertex AI provider + /// Base URL for the Azure OpenAI provider /// public string? BaseUrl { @@ -3643,7 +5813,7 @@ public string? BaseUrl } /// - /// Custom headers sent with every request to the Vertex AI provider + /// Custom headers sent with every request to the Azure OpenAI provider /// public IReadOnlyDictionary? Headers { @@ -3666,26 +5836,69 @@ public IReadOnlyDictionary? Headers } } + /// + /// Azure OpenAI resource name + /// + public string? ResourceName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("resourceName"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("resourceName", value); + } + } + + /// + /// Whether to use deployment-based Azure OpenAI URLs + /// + public bool? UseDeploymentBasedUrls + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableStruct("useDeploymentBasedUrls"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("useDeploymentBasedUrls", value); + } + } + /// public override void Validate() { - _ = this.Location; - _ = this.Project; + _ = this.ApiVersion; _ = this.BaseUrl; _ = this.Headers; + _ = this.ResourceName; + _ = this.UseDeploymentBasedUrls; } - public AgentConfigModelVertexModelConfigObjectProviderOptionsVertex() { } + public AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { } #pragma warning disable CS8618 [SetsRequiredMembers] - public AgentConfigModelVertexModelConfigObjectProviderOptionsVertex( - AgentConfigModelVertexModelConfigObjectProviderOptionsVertex agentConfigModelVertexModelConfigObjectProviderOptionsVertex + public AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure( + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure agentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure ) - : base(agentConfigModelVertexModelConfigObjectProviderOptionsVertex) { } + : base(agentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure) { } #pragma warning restore CS8618 - public AgentConfigModelVertexModelConfigObjectProviderOptionsVertex( + public AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure( IReadOnlyDictionary rawData ) { @@ -3694,7 +5907,7 @@ IReadOnlyDictionary rawData #pragma warning disable CS8618 [SetsRequiredMembers] - AgentConfigModelVertexModelConfigObjectProviderOptionsVertex( + AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure( FrozenDictionary rawData ) { @@ -3702,8 +5915,8 @@ FrozenDictionary rawData } #pragma warning restore CS8618 - /// - public static AgentConfigModelVertexModelConfigObjectProviderOptionsVertex FromRawUnchecked( + /// + public static AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure FromRawUnchecked( IReadOnlyDictionary rawData ) { @@ -3711,13 +5924,13 @@ IReadOnlyDictionary rawData } } -class AgentConfigModelVertexModelConfigObjectProviderOptionsVertexFromRaw - : IFromRawJson +class AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzureFromRaw + : IFromRawJson { /// - public AgentConfigModelVertexModelConfigObjectProviderOptionsVertex FromRawUnchecked( + public AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure FromRawUnchecked( IReadOnlyDictionary rawData - ) => AgentConfigModelVertexModelConfigObjectProviderOptionsVertex.FromRawUnchecked(rawData); + ) => AgentConfigModelAzureApiKeyModelConfigObjectProviderOptionsAzure.FromRawUnchecked(rawData); } [JsonConverter( diff --git a/src/Stagehand/Models/Sessions/SessionExtractParams.cs b/src/Stagehand/Models/Sessions/SessionExtractParams.cs index 8f06d83..8d287ad 100644 --- a/src/Stagehand/Models/Sessions/SessionExtractParams.cs +++ b/src/Stagehand/Models/Sessions/SessionExtractParams.cs @@ -440,6 +440,8 @@ public string? ModelName { return Match( vertexModelConfigObject: (x) => x.ModelName, + azureEntraModelConfigObject: (x) => x.ModelName, + azureApiKeyModelConfigObject: (x) => x.ModelName, genericModelConfigObject: (x) => x.ModelName, @string: (_) => null ); @@ -452,6 +454,8 @@ public string? ApiKey { return Match( vertexModelConfigObject: (x) => x.ApiKey, + azureEntraModelConfigObject: (_) => null, + azureApiKeyModelConfigObject: (x) => x.ApiKey, genericModelConfigObject: (x) => x.ApiKey, @string: (_) => null ); @@ -464,6 +468,8 @@ public string? BaseUrl { return Match( vertexModelConfigObject: (x) => x.BaseUrl, + azureEntraModelConfigObject: (x) => x.BaseUrl, + azureApiKeyModelConfigObject: (x) => x.BaseUrl, genericModelConfigObject: (x) => x.BaseUrl, @string: (_) => null ); @@ -479,6 +485,24 @@ public SessionExtractParamsOptionsModel( this._element = element; } + public SessionExtractParamsOptionsModel( + SessionExtractParamsOptionsModelAzureEntraModelConfigObject value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SessionExtractParamsOptionsModel( + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + public SessionExtractParamsOptionsModel( SessionExtractParamsOptionsModelGenericModelConfigObject value, JsonElement? element = null @@ -522,6 +546,52 @@ public bool TryPickVertexModelConfigObject( return value != null; } + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAzureEntraModelConfigObject(out var value)) { + /// // `value` is of type `SessionExtractParamsOptionsModelAzureEntraModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAzureEntraModelConfigObject( + [NotNullWhen(true)] out SessionExtractParamsOptionsModelAzureEntraModelConfigObject? value + ) + { + value = this.Value as SessionExtractParamsOptionsModelAzureEntraModelConfigObject; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAzureApiKeyModelConfigObject(out var value)) { + /// // `value` is of type `SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAzureApiKeyModelConfigObject( + [NotNullWhen(true)] out SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject? value + ) + { + value = this.Value as SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject; + return value != null; + } + /// /// Returns true and sets the out parameter if the instance was constructed with a variant of /// type . @@ -581,6 +651,8 @@ public bool TryPickString([NotNullWhen(true)] out string? value) /// /// instance.Switch( /// (SessionExtractParamsOptionsModelVertexModelConfigObject value) => {...}, + /// (SessionExtractParamsOptionsModelAzureEntraModelConfigObject value) => {...}, + /// (SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject value) => {...}, /// (SessionExtractParamsOptionsModelGenericModelConfigObject value) => {...}, /// (string value) => {...} /// ); @@ -589,6 +661,8 @@ public bool TryPickString([NotNullWhen(true)] out string? value) /// public void Switch( System::Action vertexModelConfigObject, + System::Action azureEntraModelConfigObject, + System::Action azureApiKeyModelConfigObject, System::Action genericModelConfigObject, System::Action @string ) @@ -598,6 +672,12 @@ public void Switch( case SessionExtractParamsOptionsModelVertexModelConfigObject value: vertexModelConfigObject(value); break; + case SessionExtractParamsOptionsModelAzureEntraModelConfigObject value: + azureEntraModelConfigObject(value); + break; + case SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject value: + azureApiKeyModelConfigObject(value); + break; case SessionExtractParamsOptionsModelGenericModelConfigObject value: genericModelConfigObject(value); break; @@ -627,6 +707,8 @@ public void Switch( /// /// var result = instance.Match( /// (SessionExtractParamsOptionsModelVertexModelConfigObject value) => {...}, + /// (SessionExtractParamsOptionsModelAzureEntraModelConfigObject value) => {...}, + /// (SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject value) => {...}, /// (SessionExtractParamsOptionsModelGenericModelConfigObject value) => {...}, /// (string value) => {...} /// ); @@ -638,6 +720,14 @@ public T Match( SessionExtractParamsOptionsModelVertexModelConfigObject, T > vertexModelConfigObject, + System::Func< + SessionExtractParamsOptionsModelAzureEntraModelConfigObject, + T + > azureEntraModelConfigObject, + System::Func< + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject, + T + > azureApiKeyModelConfigObject, System::Func< SessionExtractParamsOptionsModelGenericModelConfigObject, T @@ -649,6 +739,10 @@ public T Match( { SessionExtractParamsOptionsModelVertexModelConfigObject value => vertexModelConfigObject(value), + SessionExtractParamsOptionsModelAzureEntraModelConfigObject value => + azureEntraModelConfigObject(value), + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject value => + azureApiKeyModelConfigObject(value), SessionExtractParamsOptionsModelGenericModelConfigObject value => genericModelConfigObject(value), string value => @string(value), @@ -662,6 +756,14 @@ public static implicit operator SessionExtractParamsOptionsModel( SessionExtractParamsOptionsModelVertexModelConfigObject value ) => new(value); + public static implicit operator SessionExtractParamsOptionsModel( + SessionExtractParamsOptionsModelAzureEntraModelConfigObject value + ) => new(value); + + public static implicit operator SessionExtractParamsOptionsModel( + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject value + ) => new(value); + public static implicit operator SessionExtractParamsOptionsModel( SessionExtractParamsOptionsModelGenericModelConfigObject value ) => new(value); @@ -688,6 +790,8 @@ public override void Validate() } this.Switch( (vertexModelConfigObject) => vertexModelConfigObject.Validate(), + (azureEntraModelConfigObject) => azureEntraModelConfigObject.Validate(), + (azureApiKeyModelConfigObject) => azureApiKeyModelConfigObject.Validate(), (genericModelConfigObject) => genericModelConfigObject.Validate(), (_) => { } ); @@ -714,8 +818,10 @@ int VariantIndex() return this.Value switch { SessionExtractParamsOptionsModelVertexModelConfigObject _ => 0, - SessionExtractParamsOptionsModelGenericModelConfigObject _ => 1, - string _ => 2, + SessionExtractParamsOptionsModelAzureEntraModelConfigObject _ => 1, + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject _ => 2, + SessionExtractParamsOptionsModelGenericModelConfigObject _ => 3, + string _ => 4, _ => -1, }; } @@ -749,6 +855,42 @@ JsonSerializerOptions options // ignore } + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + try { var deserialized = @@ -1979,6 +2121,999 @@ IReadOnlyDictionary rawData ); } +[JsonConverter( + typeof(JsonModelConverter< + SessionExtractParamsOptionsModelAzureEntraModelConfigObject, + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectFromRaw + >) +)] +public sealed record class SessionExtractParamsOptionsModelAzureEntraModelConfigObject : JsonModel +{ + /// + /// Azure provider authentication configuration + /// + public required SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth Auth + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "auth" + ); + } + init { this._rawData.Set("auth", value); } + } + + /// + /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + /// + public required string ModelName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("modelName"); + } + init { this._rawData.Set("modelName", value); } + } + + /// + /// Azure OpenAI model provider + /// + public JsonElement Provider + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("provider"); + } + init { this._rawData.Set("provider", value); } + } + + /// + /// Azure provider-specific model configuration + /// + public required SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions ProviderOptions + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "providerOptions" + ); + } + init { this._rawData.Set("providerOptions", value); } + } + + /// + /// Base URL for the model provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the model provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + public override void Validate() + { + this.Auth.Validate(); + _ = this.ModelName; + if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("azure"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + this.ProviderOptions.Validate(); + _ = this.BaseUrl; + _ = this.Headers; + } + + public SessionExtractParamsOptionsModelAzureEntraModelConfigObject() + { + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionExtractParamsOptionsModelAzureEntraModelConfigObject( + SessionExtractParamsOptionsModelAzureEntraModelConfigObject sessionExtractParamsOptionsModelAzureEntraModelConfigObject + ) + : base(sessionExtractParamsOptionsModelAzureEntraModelConfigObject) { } +#pragma warning restore CS8618 + + public SessionExtractParamsOptionsModelAzureEntraModelConfigObject( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionExtractParamsOptionsModelAzureEntraModelConfigObject( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionExtractParamsOptionsModelAzureEntraModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SessionExtractParamsOptionsModelAzureEntraModelConfigObjectFromRaw + : IFromRawJson +{ + /// + public SessionExtractParamsOptionsModelAzureEntraModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SessionExtractParamsOptionsModelAzureEntraModelConfigObject.FromRawUnchecked(rawData); +} + +/// +/// Azure provider authentication configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth, + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuthFromRaw + >) +)] +public sealed record class SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth + : JsonModel +{ + /// + /// Microsoft Entra ID bearer token for Azure OpenAI + /// + public required string Token + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("token"); + } + init { this._rawData.Set("token", value); } + } + + /// + /// Use a Microsoft Entra ID bearer token for authentication + /// + public JsonElement Type + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("type"); + } + init { this._rawData.Set("type", value); } + } + + /// + public override void Validate() + { + _ = this.Token; + if (!JsonElement.DeepEquals(this.Type, JsonSerializer.SerializeToElement("azureEntraId"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + } + + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth() + { + this.Type = JsonSerializer.SerializeToElement("azureEntraId"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth( + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth sessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth + ) + : base(sessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth) { } +#pragma warning restore CS8618 + + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + + this.Type = JsonSerializer.SerializeToElement("azureEntraId"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth(string token) + : this() + { + this.Token = token; + } +} + +class SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuthFromRaw + : IFromRawJson +{ + /// + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SessionExtractParamsOptionsModelAzureEntraModelConfigObjectAuth.FromRawUnchecked(rawData); +} + +/// +/// Azure provider-specific model configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions, + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsFromRaw + >) +)] +public sealed record class SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + : JsonModel +{ + /// + /// Azure OpenAI provider-specific settings + /// + public required SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure Azure + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "azure" + ); + } + init { this._rawData.Set("azure", value); } + } + + /// + public override void Validate() + { + this.Azure.Validate(); + } + + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions( + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions sessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + ) + : base(sessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions) { } +#pragma warning restore CS8618 + + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions( + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure azure + ) + : this() + { + this.Azure = azure; + } +} + +class SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsFromRaw + : IFromRawJson +{ + /// + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptions.FromRawUnchecked( + rawData + ); +} + +/// +/// Azure OpenAI provider-specific settings +/// +[JsonConverter( + typeof(JsonModelConverter< + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure, + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzureFromRaw + >) +)] +public sealed record class SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + : JsonModel +{ + /// + /// Azure OpenAI API version + /// + public string? ApiVersion + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiVersion"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiVersion", value); + } + } + + /// + /// Base URL for the Azure OpenAI provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the Azure OpenAI provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + /// Azure OpenAI resource name + /// + public string? ResourceName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("resourceName"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("resourceName", value); + } + } + + /// + /// Whether to use deployment-based Azure OpenAI URLs + /// + public bool? UseDeploymentBasedUrls + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableStruct("useDeploymentBasedUrls"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("useDeploymentBasedUrls", value); + } + } + + /// + public override void Validate() + { + _ = this.ApiVersion; + _ = this.BaseUrl; + _ = this.Headers; + _ = this.ResourceName; + _ = this.UseDeploymentBasedUrls; + } + + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure( + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure sessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + ) + : base(sessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure) { } +#pragma warning restore CS8618 + + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzureFromRaw + : IFromRawJson +{ + /// + public SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SessionExtractParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(JsonModelConverter< + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject, + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectFromRaw + >) +)] +public sealed record class SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject : JsonModel +{ + /// + /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + /// + public required string ModelName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("modelName"); + } + init { this._rawData.Set("modelName", value); } + } + + /// + /// Azure OpenAI model provider + /// + public JsonElement Provider + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("provider"); + } + init { this._rawData.Set("provider", value); } + } + + /// + /// Azure provider-specific model configuration + /// + public required SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions ProviderOptions + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "providerOptions" + ); + } + init { this._rawData.Set("providerOptions", value); } + } + + /// + /// API key for the model provider + /// + public string? ApiKey + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiKey"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiKey", value); + } + } + + /// + /// Base URL for the model provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the model provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + public override void Validate() + { + _ = this.ModelName; + if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("azure"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + this.ProviderOptions.Validate(); + _ = this.ApiKey; + _ = this.BaseUrl; + _ = this.Headers; + } + + public SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject() + { + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject( + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject sessionExtractParamsOptionsModelAzureApiKeyModelConfigObject + ) + : base(sessionExtractParamsOptionsModelAzureApiKeyModelConfigObject) { } +#pragma warning restore CS8618 + + public SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectFromRaw + : IFromRawJson +{ + /// + public SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SessionExtractParamsOptionsModelAzureApiKeyModelConfigObject.FromRawUnchecked(rawData); +} + +/// +/// Azure provider-specific model configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions, + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsFromRaw + >) +)] +public sealed record class SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + : JsonModel +{ + /// + /// Azure OpenAI provider-specific settings + /// + public required SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure Azure + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "azure" + ); + } + init { this._rawData.Set("azure", value); } + } + + /// + public override void Validate() + { + this.Azure.Validate(); + } + + public SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions( + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions sessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + ) + : base(sessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions) { } +#pragma warning restore CS8618 + + public SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions( + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure azure + ) + : this() + { + this.Azure = azure; + } +} + +class SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsFromRaw + : IFromRawJson +{ + /// + public SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions.FromRawUnchecked( + rawData + ); +} + +/// +/// Azure OpenAI provider-specific settings +/// +[JsonConverter( + typeof(JsonModelConverter< + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure, + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzureFromRaw + >) +)] +public sealed record class SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + : JsonModel +{ + /// + /// Azure OpenAI API version + /// + public string? ApiVersion + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiVersion"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiVersion", value); + } + } + + /// + /// Base URL for the Azure OpenAI provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the Azure OpenAI provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + /// Azure OpenAI resource name + /// + public string? ResourceName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("resourceName"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("resourceName", value); + } + } + + /// + /// Whether to use deployment-based Azure OpenAI URLs + /// + public bool? UseDeploymentBasedUrls + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableStruct("useDeploymentBasedUrls"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("useDeploymentBasedUrls", value); + } + } + + /// + public override void Validate() + { + _ = this.ApiVersion; + _ = this.BaseUrl; + _ = this.Headers; + _ = this.ResourceName; + _ = this.UseDeploymentBasedUrls; + } + + public SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure( + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure sessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + ) + : base(sessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure) { } +#pragma warning restore CS8618 + + public SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzureFromRaw + : IFromRawJson +{ + /// + public SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SessionExtractParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure.FromRawUnchecked( + rawData + ); +} + [JsonConverter( typeof(JsonModelConverter< SessionExtractParamsOptionsModelGenericModelConfigObject, diff --git a/src/Stagehand/Models/Sessions/SessionObserveParams.cs b/src/Stagehand/Models/Sessions/SessionObserveParams.cs index d71c07a..0185bc6 100644 --- a/src/Stagehand/Models/Sessions/SessionObserveParams.cs +++ b/src/Stagehand/Models/Sessions/SessionObserveParams.cs @@ -426,6 +426,8 @@ public string? ModelName { return Match( vertexModelConfigObject: (x) => x.ModelName, + azureEntraModelConfigObject: (x) => x.ModelName, + azureApiKeyModelConfigObject: (x) => x.ModelName, genericModelConfigObject: (x) => x.ModelName, @string: (_) => null ); @@ -438,6 +440,8 @@ public string? ApiKey { return Match( vertexModelConfigObject: (x) => x.ApiKey, + azureEntraModelConfigObject: (_) => null, + azureApiKeyModelConfigObject: (x) => x.ApiKey, genericModelConfigObject: (x) => x.ApiKey, @string: (_) => null ); @@ -450,6 +454,8 @@ public string? BaseUrl { return Match( vertexModelConfigObject: (x) => x.BaseUrl, + azureEntraModelConfigObject: (x) => x.BaseUrl, + azureApiKeyModelConfigObject: (x) => x.BaseUrl, genericModelConfigObject: (x) => x.BaseUrl, @string: (_) => null ); @@ -465,6 +471,24 @@ public SessionObserveParamsOptionsModel( this._element = element; } + public SessionObserveParamsOptionsModel( + SessionObserveParamsOptionsModelAzureEntraModelConfigObject value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + + public SessionObserveParamsOptionsModel( + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject value, + JsonElement? element = null + ) + { + this.Value = value; + this._element = element; + } + public SessionObserveParamsOptionsModel( SessionObserveParamsOptionsModelGenericModelConfigObject value, JsonElement? element = null @@ -508,6 +532,52 @@ public bool TryPickVertexModelConfigObject( return value != null; } + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAzureEntraModelConfigObject(out var value)) { + /// // `value` is of type `SessionObserveParamsOptionsModelAzureEntraModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAzureEntraModelConfigObject( + [NotNullWhen(true)] out SessionObserveParamsOptionsModelAzureEntraModelConfigObject? value + ) + { + value = this.Value as SessionObserveParamsOptionsModelAzureEntraModelConfigObject; + return value != null; + } + + /// + /// Returns true and sets the out parameter if the instance was constructed with a variant of + /// type . + /// + /// Consider using or if you need to handle every variant. + /// + /// + /// + /// if (instance.TryPickAzureApiKeyModelConfigObject(out var value)) { + /// // `value` is of type `SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject` + /// Console.WriteLine(value); + /// } + /// + /// + /// + public bool TryPickAzureApiKeyModelConfigObject( + [NotNullWhen(true)] out SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject? value + ) + { + value = this.Value as SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject; + return value != null; + } + /// /// Returns true and sets the out parameter if the instance was constructed with a variant of /// type . @@ -567,6 +637,8 @@ public bool TryPickString([NotNullWhen(true)] out string? value) /// /// instance.Switch( /// (SessionObserveParamsOptionsModelVertexModelConfigObject value) => {...}, + /// (SessionObserveParamsOptionsModelAzureEntraModelConfigObject value) => {...}, + /// (SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject value) => {...}, /// (SessionObserveParamsOptionsModelGenericModelConfigObject value) => {...}, /// (string value) => {...} /// ); @@ -575,6 +647,8 @@ public bool TryPickString([NotNullWhen(true)] out string? value) /// public void Switch( System::Action vertexModelConfigObject, + System::Action azureEntraModelConfigObject, + System::Action azureApiKeyModelConfigObject, System::Action genericModelConfigObject, System::Action @string ) @@ -584,6 +658,12 @@ public void Switch( case SessionObserveParamsOptionsModelVertexModelConfigObject value: vertexModelConfigObject(value); break; + case SessionObserveParamsOptionsModelAzureEntraModelConfigObject value: + azureEntraModelConfigObject(value); + break; + case SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject value: + azureApiKeyModelConfigObject(value); + break; case SessionObserveParamsOptionsModelGenericModelConfigObject value: genericModelConfigObject(value); break; @@ -613,6 +693,8 @@ public void Switch( /// /// var result = instance.Match( /// (SessionObserveParamsOptionsModelVertexModelConfigObject value) => {...}, + /// (SessionObserveParamsOptionsModelAzureEntraModelConfigObject value) => {...}, + /// (SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject value) => {...}, /// (SessionObserveParamsOptionsModelGenericModelConfigObject value) => {...}, /// (string value) => {...} /// ); @@ -624,6 +706,14 @@ public T Match( SessionObserveParamsOptionsModelVertexModelConfigObject, T > vertexModelConfigObject, + System::Func< + SessionObserveParamsOptionsModelAzureEntraModelConfigObject, + T + > azureEntraModelConfigObject, + System::Func< + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject, + T + > azureApiKeyModelConfigObject, System::Func< SessionObserveParamsOptionsModelGenericModelConfigObject, T @@ -635,6 +725,10 @@ public T Match( { SessionObserveParamsOptionsModelVertexModelConfigObject value => vertexModelConfigObject(value), + SessionObserveParamsOptionsModelAzureEntraModelConfigObject value => + azureEntraModelConfigObject(value), + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject value => + azureApiKeyModelConfigObject(value), SessionObserveParamsOptionsModelGenericModelConfigObject value => genericModelConfigObject(value), string value => @string(value), @@ -648,6 +742,14 @@ public static implicit operator SessionObserveParamsOptionsModel( SessionObserveParamsOptionsModelVertexModelConfigObject value ) => new(value); + public static implicit operator SessionObserveParamsOptionsModel( + SessionObserveParamsOptionsModelAzureEntraModelConfigObject value + ) => new(value); + + public static implicit operator SessionObserveParamsOptionsModel( + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject value + ) => new(value); + public static implicit operator SessionObserveParamsOptionsModel( SessionObserveParamsOptionsModelGenericModelConfigObject value ) => new(value); @@ -674,6 +776,8 @@ public override void Validate() } this.Switch( (vertexModelConfigObject) => vertexModelConfigObject.Validate(), + (azureEntraModelConfigObject) => azureEntraModelConfigObject.Validate(), + (azureApiKeyModelConfigObject) => azureApiKeyModelConfigObject.Validate(), (genericModelConfigObject) => genericModelConfigObject.Validate(), (_) => { } ); @@ -700,8 +804,10 @@ int VariantIndex() return this.Value switch { SessionObserveParamsOptionsModelVertexModelConfigObject _ => 0, - SessionObserveParamsOptionsModelGenericModelConfigObject _ => 1, - string _ => 2, + SessionObserveParamsOptionsModelAzureEntraModelConfigObject _ => 1, + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject _ => 2, + SessionObserveParamsOptionsModelGenericModelConfigObject _ => 3, + string _ => 4, _ => -1, }; } @@ -735,6 +841,42 @@ JsonSerializerOptions options // ignore } + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + + try + { + var deserialized = + JsonSerializer.Deserialize( + element, + options + ); + if (deserialized != null) + { + deserialized.Validate(); + return new(deserialized, element); + } + } + catch (System::Exception e) when (e is JsonException || e is StagehandInvalidDataException) + { + // ignore + } + try { var deserialized = @@ -1965,6 +2107,999 @@ IReadOnlyDictionary rawData ); } +[JsonConverter( + typeof(JsonModelConverter< + SessionObserveParamsOptionsModelAzureEntraModelConfigObject, + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectFromRaw + >) +)] +public sealed record class SessionObserveParamsOptionsModelAzureEntraModelConfigObject : JsonModel +{ + /// + /// Azure provider authentication configuration + /// + public required SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth Auth + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "auth" + ); + } + init { this._rawData.Set("auth", value); } + } + + /// + /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + /// + public required string ModelName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("modelName"); + } + init { this._rawData.Set("modelName", value); } + } + + /// + /// Azure OpenAI model provider + /// + public JsonElement Provider + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("provider"); + } + init { this._rawData.Set("provider", value); } + } + + /// + /// Azure provider-specific model configuration + /// + public required SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions ProviderOptions + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "providerOptions" + ); + } + init { this._rawData.Set("providerOptions", value); } + } + + /// + /// Base URL for the model provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the model provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + public override void Validate() + { + this.Auth.Validate(); + _ = this.ModelName; + if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("azure"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + this.ProviderOptions.Validate(); + _ = this.BaseUrl; + _ = this.Headers; + } + + public SessionObserveParamsOptionsModelAzureEntraModelConfigObject() + { + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionObserveParamsOptionsModelAzureEntraModelConfigObject( + SessionObserveParamsOptionsModelAzureEntraModelConfigObject sessionObserveParamsOptionsModelAzureEntraModelConfigObject + ) + : base(sessionObserveParamsOptionsModelAzureEntraModelConfigObject) { } +#pragma warning restore CS8618 + + public SessionObserveParamsOptionsModelAzureEntraModelConfigObject( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionObserveParamsOptionsModelAzureEntraModelConfigObject( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionObserveParamsOptionsModelAzureEntraModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SessionObserveParamsOptionsModelAzureEntraModelConfigObjectFromRaw + : IFromRawJson +{ + /// + public SessionObserveParamsOptionsModelAzureEntraModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SessionObserveParamsOptionsModelAzureEntraModelConfigObject.FromRawUnchecked(rawData); +} + +/// +/// Azure provider authentication configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth, + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuthFromRaw + >) +)] +public sealed record class SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth + : JsonModel +{ + /// + /// Microsoft Entra ID bearer token for Azure OpenAI + /// + public required string Token + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("token"); + } + init { this._rawData.Set("token", value); } + } + + /// + /// Use a Microsoft Entra ID bearer token for authentication + /// + public JsonElement Type + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("type"); + } + init { this._rawData.Set("type", value); } + } + + /// + public override void Validate() + { + _ = this.Token; + if (!JsonElement.DeepEquals(this.Type, JsonSerializer.SerializeToElement("azureEntraId"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + } + + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth() + { + this.Type = JsonSerializer.SerializeToElement("azureEntraId"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth( + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth sessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth + ) + : base(sessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth) { } +#pragma warning restore CS8618 + + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + + this.Type = JsonSerializer.SerializeToElement("azureEntraId"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth(string token) + : this() + { + this.Token = token; + } +} + +class SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuthFromRaw + : IFromRawJson +{ + /// + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SessionObserveParamsOptionsModelAzureEntraModelConfigObjectAuth.FromRawUnchecked(rawData); +} + +/// +/// Azure provider-specific model configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions, + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsFromRaw + >) +)] +public sealed record class SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + : JsonModel +{ + /// + /// Azure OpenAI provider-specific settings + /// + public required SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure Azure + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "azure" + ); + } + init { this._rawData.Set("azure", value); } + } + + /// + public override void Validate() + { + this.Azure.Validate(); + } + + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions( + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions sessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions + ) + : base(sessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions) { } +#pragma warning restore CS8618 + + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions( + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure azure + ) + : this() + { + this.Azure = azure; + } +} + +class SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsFromRaw + : IFromRawJson +{ + /// + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptions.FromRawUnchecked( + rawData + ); +} + +/// +/// Azure OpenAI provider-specific settings +/// +[JsonConverter( + typeof(JsonModelConverter< + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure, + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzureFromRaw + >) +)] +public sealed record class SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + : JsonModel +{ + /// + /// Azure OpenAI API version + /// + public string? ApiVersion + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiVersion"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiVersion", value); + } + } + + /// + /// Base URL for the Azure OpenAI provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the Azure OpenAI provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + /// Azure OpenAI resource name + /// + public string? ResourceName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("resourceName"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("resourceName", value); + } + } + + /// + /// Whether to use deployment-based Azure OpenAI URLs + /// + public bool? UseDeploymentBasedUrls + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableStruct("useDeploymentBasedUrls"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("useDeploymentBasedUrls", value); + } + } + + /// + public override void Validate() + { + _ = this.ApiVersion; + _ = this.BaseUrl; + _ = this.Headers; + _ = this.ResourceName; + _ = this.UseDeploymentBasedUrls; + } + + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure( + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure sessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure + ) + : base(sessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure) { } +#pragma warning restore CS8618 + + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzureFromRaw + : IFromRawJson +{ + /// + public SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SessionObserveParamsOptionsModelAzureEntraModelConfigObjectProviderOptionsAzure.FromRawUnchecked( + rawData + ); +} + +[JsonConverter( + typeof(JsonModelConverter< + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject, + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectFromRaw + >) +)] +public sealed record class SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject : JsonModel +{ + /// + /// Model name string with provider prefix (e.g., 'openai/gpt-5-nano') + /// + public required string ModelName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass("modelName"); + } + init { this._rawData.Set("modelName", value); } + } + + /// + /// Azure OpenAI model provider + /// + public JsonElement Provider + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullStruct("provider"); + } + init { this._rawData.Set("provider", value); } + } + + /// + /// Azure provider-specific model configuration + /// + public required SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions ProviderOptions + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "providerOptions" + ); + } + init { this._rawData.Set("providerOptions", value); } + } + + /// + /// API key for the model provider + /// + public string? ApiKey + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiKey"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiKey", value); + } + } + + /// + /// Base URL for the model provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the model provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + public override void Validate() + { + _ = this.ModelName; + if (!JsonElement.DeepEquals(this.Provider, JsonSerializer.SerializeToElement("azure"))) + { + throw new StagehandInvalidDataException("Invalid value given for constant"); + } + this.ProviderOptions.Validate(); + _ = this.ApiKey; + _ = this.BaseUrl; + _ = this.Headers; + } + + public SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject() + { + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject( + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject sessionObserveParamsOptionsModelAzureApiKeyModelConfigObject + ) + : base(sessionObserveParamsOptionsModelAzureApiKeyModelConfigObject) { } +#pragma warning restore CS8618 + + public SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + + this.Provider = JsonSerializer.SerializeToElement("azure"); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectFromRaw + : IFromRawJson +{ + /// + public SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject FromRawUnchecked( + IReadOnlyDictionary rawData + ) => SessionObserveParamsOptionsModelAzureApiKeyModelConfigObject.FromRawUnchecked(rawData); +} + +/// +/// Azure provider-specific model configuration +/// +[JsonConverter( + typeof(JsonModelConverter< + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions, + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsFromRaw + >) +)] +public sealed record class SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + : JsonModel +{ + /// + /// Azure OpenAI provider-specific settings + /// + public required SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure Azure + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNotNullClass( + "azure" + ); + } + init { this._rawData.Set("azure", value); } + } + + /// + public override void Validate() + { + this.Azure.Validate(); + } + + public SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions( + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions sessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions + ) + : base(sessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions) { } +#pragma warning restore CS8618 + + public SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } + + [SetsRequiredMembers] + public SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions( + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure azure + ) + : this() + { + this.Azure = azure; + } +} + +class SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsFromRaw + : IFromRawJson +{ + /// + public SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptions.FromRawUnchecked( + rawData + ); +} + +/// +/// Azure OpenAI provider-specific settings +/// +[JsonConverter( + typeof(JsonModelConverter< + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure, + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzureFromRaw + >) +)] +public sealed record class SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + : JsonModel +{ + /// + /// Azure OpenAI API version + /// + public string? ApiVersion + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("apiVersion"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("apiVersion", value); + } + } + + /// + /// Base URL for the Azure OpenAI provider + /// + public string? BaseUrl + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("baseURL"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("baseURL", value); + } + } + + /// + /// Custom headers sent with every request to the Azure OpenAI provider + /// + public IReadOnlyDictionary? Headers + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>("headers"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set?>( + "headers", + value == null ? null : FrozenDictionary.ToFrozenDictionary(value) + ); + } + } + + /// + /// Azure OpenAI resource name + /// + public string? ResourceName + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass("resourceName"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("resourceName", value); + } + } + + /// + /// Whether to use deployment-based Azure OpenAI URLs + /// + public bool? UseDeploymentBasedUrls + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableStruct("useDeploymentBasedUrls"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("useDeploymentBasedUrls", value); + } + } + + /// + public override void Validate() + { + _ = this.ApiVersion; + _ = this.BaseUrl; + _ = this.Headers; + _ = this.ResourceName; + _ = this.UseDeploymentBasedUrls; + } + + public SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure() { } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + public SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure( + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure sessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure + ) + : base(sessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure) { } +#pragma warning restore CS8618 + + public SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure( + IReadOnlyDictionary rawData + ) + { + this._rawData = new(rawData); + } + +#pragma warning disable CS8618 + [SetsRequiredMembers] + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure( + FrozenDictionary rawData + ) + { + this._rawData = new(rawData); + } +#pragma warning restore CS8618 + + /// + public static SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) + { + return new(FrozenDictionary.ToFrozenDictionary(rawData)); + } +} + +class SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzureFromRaw + : IFromRawJson +{ + /// + public SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure FromRawUnchecked( + IReadOnlyDictionary rawData + ) => + SessionObserveParamsOptionsModelAzureApiKeyModelConfigObjectProviderOptionsAzure.FromRawUnchecked( + rawData + ); +} + [JsonConverter( typeof(JsonModelConverter< SessionObserveParamsOptionsModelGenericModelConfigObject, From 21b8d30f5b2d75636d77521c9ebe255be396a756 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 02:00:34 +0000 Subject: [PATCH 3/6] feat(stlc): configurable CI runner and private-production-repo support in workflow templates --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca841c8..a48e4be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: lint: timeout-minutes: 10 name: lint - runs-on: ${{ github.repository == 'stainless-sdks/stagehand-csharp' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: @@ -37,7 +37,7 @@ jobs: build: timeout-minutes: 10 name: build - runs-on: ${{ github.repository == 'stainless-sdks/stagehand-csharp' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: @@ -54,7 +54,7 @@ jobs: test: timeout-minutes: 10 name: test - runs-on: ${{ github.repository == 'stainless-sdks/stagehand-csharp' && 'depot-windows-2022' || 'windows-latest' }} + runs-on: ${{ startsWith(github.repository, 'stainless-sdks/') && 'depot-windows-2022' || 'windows-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 From eb515f8aa3a8d6d508cc5e3d3c4f8e598744f57d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2026 23:38:02 +0000 Subject: [PATCH 4/6] feat(server-v3): expose OpenAI endpoint format --- .stats.yml | 4 +- .../Models/Sessions/ModelConfigTest.cs | 81 ++++++++ .../Models/Sessions/SessionActParamsTest.cs | 75 ++++++++ .../Sessions/SessionExecuteParamsTest.cs | 177 ++++++++++++++++++ .../Sessions/SessionExtractParamsTest.cs | 113 +++++++++++ .../Sessions/SessionObserveParamsTest.cs | 113 +++++++++++ src/Stagehand/Core/ModelBase.cs | 18 ++ src/Stagehand/Models/Sessions/ModelConfig.cs | 77 ++++++++ .../Models/Sessions/SessionActParams.cs | 73 ++++++++ .../Models/Sessions/SessionExecuteParams.cs | 155 +++++++++++++++ .../Models/Sessions/SessionExtractParams.cs | 86 +++++++++ .../Models/Sessions/SessionObserveParams.cs | 86 +++++++++ 12 files changed, 1056 insertions(+), 2 deletions(-) diff --git a/.stats.yml b/.stats.yml index 90ce078..7b1f04d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 8 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-4d0d50b4f18fd74f58aca0b84d6968d1228499f2fa4e5714516f13ff6f820c9d.yml -openapi_spec_hash: f7b1a869f3e412aea4d4bd42467791bb +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/browserbase/stagehand-64b47a6dd07208d708130e739a272f7d37d4e42494a7c8e566ef66007f8ff25f.yml +openapi_spec_hash: 4cdfcfed592c8631fbab9117bf45bb67 config_hash: 1fb12ae9b478488bc1e56bfbdc210b01 diff --git a/src/Stagehand.Tests/Models/Sessions/ModelConfigTest.cs b/src/Stagehand.Tests/Models/Sessions/ModelConfigTest.cs index 5d910c7..c35acab 100644 --- a/src/Stagehand.Tests/Models/Sessions/ModelConfigTest.cs +++ b/src/Stagehand.Tests/Models/Sessions/ModelConfigTest.cs @@ -105,6 +105,7 @@ public void GenericModelConfigObjectValidationWorks() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ModelConfigGenericModelConfigObjectProvider.OpenAI, }; value.Validate(); @@ -225,6 +226,7 @@ public void GenericModelConfigObjectSerializationRoundtripWorks() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ModelConfigGenericModelConfigObjectProvider.OpenAI, }; string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); @@ -3053,6 +3055,7 @@ public void FieldRoundtrip_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ModelConfigGenericModelConfigObjectProvider.OpenAI, }; @@ -3060,6 +3063,11 @@ public void FieldRoundtrip_Works() string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum< + string, + ModelConfigGenericModelConfigObjectOpenAIEndpointFormat + > expectedOpenAIEndpointFormat = + ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Chat; ApiEnum expectedProvider = ModelConfigGenericModelConfigObjectProvider.OpenAI; @@ -3074,6 +3082,7 @@ public void FieldRoundtrip_Works() Assert.Equal(value, model.Headers[item.Key]); } + Assert.Equal(expectedOpenAIEndpointFormat, model.OpenAIEndpointFormat); Assert.Equal(expectedProvider, model.Provider); } @@ -3086,6 +3095,7 @@ public void SerializationRoundtrip_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ModelConfigGenericModelConfigObjectProvider.OpenAI, }; @@ -3107,6 +3117,7 @@ public void FieldRoundtripThroughSerialization_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ModelConfigGenericModelConfigObjectProvider.OpenAI, }; @@ -3121,6 +3132,11 @@ public void FieldRoundtripThroughSerialization_Works() string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum< + string, + ModelConfigGenericModelConfigObjectOpenAIEndpointFormat + > expectedOpenAIEndpointFormat = + ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Chat; ApiEnum expectedProvider = ModelConfigGenericModelConfigObjectProvider.OpenAI; @@ -3135,6 +3151,7 @@ public void FieldRoundtripThroughSerialization_Works() Assert.Equal(value, deserialized.Headers[item.Key]); } + Assert.Equal(expectedOpenAIEndpointFormat, deserialized.OpenAIEndpointFormat); Assert.Equal(expectedProvider, deserialized.Provider); } @@ -3147,6 +3164,7 @@ public void Validation_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ModelConfigGenericModelConfigObjectProvider.OpenAI, }; @@ -3164,6 +3182,8 @@ public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.OpenAIEndpointFormat); + Assert.False(model.RawData.ContainsKey("openaiEndpointFormat")); Assert.Null(model.Provider); Assert.False(model.RawData.ContainsKey("provider")); } @@ -3187,6 +3207,7 @@ public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() ApiKey = null, BaseUrl = null, Headers = null, + OpenAIEndpointFormat = null, Provider = null, }; @@ -3196,6 +3217,8 @@ public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.OpenAIEndpointFormat); + Assert.False(model.RawData.ContainsKey("openaiEndpointFormat")); Assert.Null(model.Provider); Assert.False(model.RawData.ContainsKey("provider")); } @@ -3211,6 +3234,7 @@ public void OptionalNonNullablePropertiesSetToNullValidation_Works() ApiKey = null, BaseUrl = null, Headers = null, + OpenAIEndpointFormat = null, Provider = null, }; @@ -3226,6 +3250,7 @@ public void CopyConstructor_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ModelConfigGenericModelConfigObjectProvider.OpenAI, }; @@ -3235,6 +3260,62 @@ public void CopyConstructor_Works() } } +public class ModelConfigGenericModelConfigObjectOpenAIEndpointFormatTest : TestBase +{ + [Theory] + [InlineData(ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Responses)] + [InlineData(ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Chat)] + public void Validation_Works(ModelConfigGenericModelConfigObjectOpenAIEndpointFormat rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Responses)] + [InlineData(ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Chat)] + public void SerializationRoundtrip_Works( + ModelConfigGenericModelConfigObjectOpenAIEndpointFormat rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + public class ModelConfigGenericModelConfigObjectProviderTest : TestBase { [Theory] diff --git a/src/Stagehand.Tests/Models/Sessions/SessionActParamsTest.cs b/src/Stagehand.Tests/Models/Sessions/SessionActParamsTest.cs index a7f1593..adf813f 100644 --- a/src/Stagehand.Tests/Models/Sessions/SessionActParamsTest.cs +++ b/src/Stagehand.Tests/Models/Sessions/SessionActParamsTest.cs @@ -1070,6 +1070,7 @@ public void GenericModelConfigObjectValidationWorks() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = Sessions::OpenAIEndpointFormat.Chat, Provider = Sessions::Provider.OpenAI, }; value.Validate(); @@ -1197,6 +1198,7 @@ public void GenericModelConfigObjectSerializationRoundtripWorks() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = Sessions::OpenAIEndpointFormat.Chat, Provider = Sessions::Provider.OpenAI, }; string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); @@ -4022,6 +4024,7 @@ public void FieldRoundtrip_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = Sessions::OpenAIEndpointFormat.Chat, Provider = Sessions::Provider.OpenAI, }; @@ -4029,6 +4032,8 @@ public void FieldRoundtrip_Works() string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum expectedOpenAIEndpointFormat = + Sessions::OpenAIEndpointFormat.Chat; ApiEnum expectedProvider = Sessions::Provider.OpenAI; Assert.Equal(expectedModelName, model.ModelName); @@ -4042,6 +4047,7 @@ public void FieldRoundtrip_Works() Assert.Equal(value, model.Headers[item.Key]); } + Assert.Equal(expectedOpenAIEndpointFormat, model.OpenAIEndpointFormat); Assert.Equal(expectedProvider, model.Provider); } @@ -4054,6 +4060,7 @@ public void SerializationRoundtrip_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = Sessions::OpenAIEndpointFormat.Chat, Provider = Sessions::Provider.OpenAI, }; @@ -4075,6 +4082,7 @@ public void FieldRoundtripThroughSerialization_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = Sessions::OpenAIEndpointFormat.Chat, Provider = Sessions::Provider.OpenAI, }; @@ -4089,6 +4097,8 @@ public void FieldRoundtripThroughSerialization_Works() string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum expectedOpenAIEndpointFormat = + Sessions::OpenAIEndpointFormat.Chat; ApiEnum expectedProvider = Sessions::Provider.OpenAI; Assert.Equal(expectedModelName, deserialized.ModelName); @@ -4102,6 +4112,7 @@ public void FieldRoundtripThroughSerialization_Works() Assert.Equal(value, deserialized.Headers[item.Key]); } + Assert.Equal(expectedOpenAIEndpointFormat, deserialized.OpenAIEndpointFormat); Assert.Equal(expectedProvider, deserialized.Provider); } @@ -4114,6 +4125,7 @@ public void Validation_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = Sessions::OpenAIEndpointFormat.Chat, Provider = Sessions::Provider.OpenAI, }; @@ -4131,6 +4143,8 @@ public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.OpenAIEndpointFormat); + Assert.False(model.RawData.ContainsKey("openaiEndpointFormat")); Assert.Null(model.Provider); Assert.False(model.RawData.ContainsKey("provider")); } @@ -4154,6 +4168,7 @@ public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() ApiKey = null, BaseUrl = null, Headers = null, + OpenAIEndpointFormat = null, Provider = null, }; @@ -4163,6 +4178,8 @@ public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.OpenAIEndpointFormat); + Assert.False(model.RawData.ContainsKey("openaiEndpointFormat")); Assert.Null(model.Provider); Assert.False(model.RawData.ContainsKey("provider")); } @@ -4178,6 +4195,7 @@ public void OptionalNonNullablePropertiesSetToNullValidation_Works() ApiKey = null, BaseUrl = null, Headers = null, + OpenAIEndpointFormat = null, Provider = null, }; @@ -4193,6 +4211,7 @@ public void CopyConstructor_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = Sessions::OpenAIEndpointFormat.Chat, Provider = Sessions::Provider.OpenAI, }; @@ -4202,6 +4221,62 @@ public void CopyConstructor_Works() } } +public class OpenAIEndpointFormatTest : TestBase +{ + [Theory] + [InlineData(Sessions::OpenAIEndpointFormat.Responses)] + [InlineData(Sessions::OpenAIEndpointFormat.Chat)] + public void Validation_Works(Sessions::OpenAIEndpointFormat rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.SerializeToElement("invalid value"), + ModelBase.SerializerOptions + ); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(Sessions::OpenAIEndpointFormat.Responses)] + [InlineData(Sessions::OpenAIEndpointFormat.Chat)] + public void SerializationRoundtrip_Works(Sessions::OpenAIEndpointFormat rawValue) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize>( + JsonSerializer.SerializeToElement("invalid value"), + ModelBase.SerializerOptions + ); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + public class ProviderTest : TestBase { [Theory] diff --git a/src/Stagehand.Tests/Models/Sessions/SessionExecuteParamsTest.cs b/src/Stagehand.Tests/Models/Sessions/SessionExecuteParamsTest.cs index 7104aea..f129508 100644 --- a/src/Stagehand.Tests/Models/Sessions/SessionExecuteParamsTest.cs +++ b/src/Stagehand.Tests/Models/Sessions/SessionExecuteParamsTest.cs @@ -1804,6 +1804,7 @@ public void GenericModelConfigObjectValidationWorks() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, }; value.Validate(); @@ -1931,6 +1932,7 @@ public void GenericModelConfigObjectSerializationRoundtripWorks() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, }; string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); @@ -4776,6 +4778,7 @@ public void FieldRoundtrip_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4783,6 +4786,11 @@ public void FieldRoundtrip_Works() string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum< + string, + ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat + > expectedOpenAIEndpointFormat = + ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Chat; ApiEnum expectedProvider = ExecutionModelGenericModelConfigObjectProvider.OpenAI; @@ -4797,6 +4805,7 @@ public void FieldRoundtrip_Works() Assert.Equal(value, model.Headers[item.Key]); } + Assert.Equal(expectedOpenAIEndpointFormat, model.OpenAIEndpointFormat); Assert.Equal(expectedProvider, model.Provider); } @@ -4809,6 +4818,7 @@ public void SerializationRoundtrip_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4830,6 +4840,7 @@ public void FieldRoundtripThroughSerialization_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4844,6 +4855,11 @@ public void FieldRoundtripThroughSerialization_Works() string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum< + string, + ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat + > expectedOpenAIEndpointFormat = + ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Chat; ApiEnum expectedProvider = ExecutionModelGenericModelConfigObjectProvider.OpenAI; @@ -4858,6 +4874,7 @@ public void FieldRoundtripThroughSerialization_Works() Assert.Equal(value, deserialized.Headers[item.Key]); } + Assert.Equal(expectedOpenAIEndpointFormat, deserialized.OpenAIEndpointFormat); Assert.Equal(expectedProvider, deserialized.Provider); } @@ -4870,6 +4887,7 @@ public void Validation_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4890,6 +4908,8 @@ public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.OpenAIEndpointFormat); + Assert.False(model.RawData.ContainsKey("openaiEndpointFormat")); Assert.Null(model.Provider); Assert.False(model.RawData.ContainsKey("provider")); } @@ -4916,6 +4936,7 @@ public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() ApiKey = null, BaseUrl = null, Headers = null, + OpenAIEndpointFormat = null, Provider = null, }; @@ -4925,6 +4946,8 @@ public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.OpenAIEndpointFormat); + Assert.False(model.RawData.ContainsKey("openaiEndpointFormat")); Assert.Null(model.Provider); Assert.False(model.RawData.ContainsKey("provider")); } @@ -4940,6 +4963,7 @@ public void OptionalNonNullablePropertiesSetToNullValidation_Works() ApiKey = null, BaseUrl = null, Headers = null, + OpenAIEndpointFormat = null, Provider = null, }; @@ -4955,6 +4979,7 @@ public void CopyConstructor_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = ExecutionModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4964,6 +4989,66 @@ public void CopyConstructor_Works() } } +public class ExecutionModelGenericModelConfigObjectOpenAIEndpointFormatTest : TestBase +{ + [Theory] + [InlineData(ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Responses)] + [InlineData(ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Chat)] + public void Validation_Works( + ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Responses)] + [InlineData(ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Chat)] + public void SerializationRoundtrip_Works( + ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + public class ExecutionModelGenericModelConfigObjectProviderTest : TestBase { [Theory] @@ -5186,6 +5271,8 @@ public void GenericModelConfigObjectValidationWorks() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = AgentConfigModelGenericModelConfigObjectProvider.OpenAI, }; value.Validate(); @@ -5314,6 +5401,8 @@ public void GenericModelConfigObjectSerializationRoundtripWorks() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = AgentConfigModelGenericModelConfigObjectProvider.OpenAI, }; string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); @@ -8172,6 +8261,8 @@ public void FieldRoundtrip_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = AgentConfigModelGenericModelConfigObjectProvider.OpenAI, }; @@ -8179,6 +8270,11 @@ public void FieldRoundtrip_Works() string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum< + string, + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat + > expectedOpenAIEndpointFormat = + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Chat; ApiEnum expectedProvider = AgentConfigModelGenericModelConfigObjectProvider.OpenAI; @@ -8193,6 +8289,7 @@ public void FieldRoundtrip_Works() Assert.Equal(value, model.Headers[item.Key]); } + Assert.Equal(expectedOpenAIEndpointFormat, model.OpenAIEndpointFormat); Assert.Equal(expectedProvider, model.Provider); } @@ -8205,6 +8302,8 @@ public void SerializationRoundtrip_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = AgentConfigModelGenericModelConfigObjectProvider.OpenAI, }; @@ -8226,6 +8325,8 @@ public void FieldRoundtripThroughSerialization_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = AgentConfigModelGenericModelConfigObjectProvider.OpenAI, }; @@ -8240,6 +8341,11 @@ public void FieldRoundtripThroughSerialization_Works() string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum< + string, + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat + > expectedOpenAIEndpointFormat = + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Chat; ApiEnum expectedProvider = AgentConfigModelGenericModelConfigObjectProvider.OpenAI; @@ -8254,6 +8360,7 @@ public void FieldRoundtripThroughSerialization_Works() Assert.Equal(value, deserialized.Headers[item.Key]); } + Assert.Equal(expectedOpenAIEndpointFormat, deserialized.OpenAIEndpointFormat); Assert.Equal(expectedProvider, deserialized.Provider); } @@ -8266,6 +8373,8 @@ public void Validation_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = AgentConfigModelGenericModelConfigObjectProvider.OpenAI, }; @@ -8286,6 +8395,8 @@ public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.OpenAIEndpointFormat); + Assert.False(model.RawData.ContainsKey("openaiEndpointFormat")); Assert.Null(model.Provider); Assert.False(model.RawData.ContainsKey("provider")); } @@ -8312,6 +8423,7 @@ public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() ApiKey = null, BaseUrl = null, Headers = null, + OpenAIEndpointFormat = null, Provider = null, }; @@ -8321,6 +8433,8 @@ public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.OpenAIEndpointFormat); + Assert.False(model.RawData.ContainsKey("openaiEndpointFormat")); Assert.Null(model.Provider); Assert.False(model.RawData.ContainsKey("provider")); } @@ -8336,6 +8450,7 @@ public void OptionalNonNullablePropertiesSetToNullValidation_Works() ApiKey = null, BaseUrl = null, Headers = null, + OpenAIEndpointFormat = null, Provider = null, }; @@ -8351,6 +8466,8 @@ public void CopyConstructor_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = AgentConfigModelGenericModelConfigObjectProvider.OpenAI, }; @@ -8360,6 +8477,66 @@ public void CopyConstructor_Works() } } +public class AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormatTest : TestBase +{ + [Theory] + [InlineData(AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Responses)] + [InlineData(AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Chat)] + public void Validation_Works( + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData(AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Responses)] + [InlineData(AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Chat)] + public void SerializationRoundtrip_Works( + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum value = + rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + public class AgentConfigModelGenericModelConfigObjectProviderTest : TestBase { [Theory] diff --git a/src/Stagehand.Tests/Models/Sessions/SessionExtractParamsTest.cs b/src/Stagehand.Tests/Models/Sessions/SessionExtractParamsTest.cs index 1188751..e02262b 100644 --- a/src/Stagehand.Tests/Models/Sessions/SessionExtractParamsTest.cs +++ b/src/Stagehand.Tests/Models/Sessions/SessionExtractParamsTest.cs @@ -967,6 +967,8 @@ public void GenericModelConfigObjectValidationWorks() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionExtractParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; value.Validate(); @@ -1099,6 +1101,8 @@ public void GenericModelConfigObjectSerializationRoundtripWorks() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionExtractParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); @@ -4072,6 +4076,8 @@ public void FieldRoundtrip_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionExtractParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4079,6 +4085,11 @@ public void FieldRoundtrip_Works() string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum< + string, + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > expectedOpenAIEndpointFormat = + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat; ApiEnum< string, SessionExtractParamsOptionsModelGenericModelConfigObjectProvider @@ -4096,6 +4107,7 @@ public void FieldRoundtrip_Works() Assert.Equal(value, model.Headers[item.Key]); } + Assert.Equal(expectedOpenAIEndpointFormat, model.OpenAIEndpointFormat); Assert.Equal(expectedProvider, model.Provider); } @@ -4108,6 +4120,8 @@ public void SerializationRoundtrip_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionExtractParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4130,6 +4144,8 @@ public void FieldRoundtripThroughSerialization_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionExtractParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4145,6 +4161,11 @@ public void FieldRoundtripThroughSerialization_Works() string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum< + string, + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > expectedOpenAIEndpointFormat = + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat; ApiEnum< string, SessionExtractParamsOptionsModelGenericModelConfigObjectProvider @@ -4162,6 +4183,7 @@ public void FieldRoundtripThroughSerialization_Works() Assert.Equal(value, deserialized.Headers[item.Key]); } + Assert.Equal(expectedOpenAIEndpointFormat, deserialized.OpenAIEndpointFormat); Assert.Equal(expectedProvider, deserialized.Provider); } @@ -4174,6 +4196,8 @@ public void Validation_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionExtractParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4194,6 +4218,8 @@ public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.OpenAIEndpointFormat); + Assert.False(model.RawData.ContainsKey("openaiEndpointFormat")); Assert.Null(model.Provider); Assert.False(model.RawData.ContainsKey("provider")); } @@ -4220,6 +4246,7 @@ public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() ApiKey = null, BaseUrl = null, Headers = null, + OpenAIEndpointFormat = null, Provider = null, }; @@ -4229,6 +4256,8 @@ public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.OpenAIEndpointFormat); + Assert.False(model.RawData.ContainsKey("openaiEndpointFormat")); Assert.Null(model.Provider); Assert.False(model.RawData.ContainsKey("provider")); } @@ -4244,6 +4273,7 @@ public void OptionalNonNullablePropertiesSetToNullValidation_Works() ApiKey = null, BaseUrl = null, Headers = null, + OpenAIEndpointFormat = null, Provider = null, }; @@ -4259,6 +4289,8 @@ public void CopyConstructor_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionExtractParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4268,6 +4300,87 @@ public void CopyConstructor_Works() } } +public class SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormatTest + : TestBase +{ + [Theory] + [InlineData( + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Responses + )] + [InlineData(SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat)] + public void Validation_Works( + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Responses + )] + [InlineData(SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat)] + public void SerializationRoundtrip_Works( + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + public class SessionExtractParamsOptionsModelGenericModelConfigObjectProviderTest : TestBase { [Theory] diff --git a/src/Stagehand.Tests/Models/Sessions/SessionObserveParamsTest.cs b/src/Stagehand.Tests/Models/Sessions/SessionObserveParamsTest.cs index 81a2142..0e49293 100644 --- a/src/Stagehand.Tests/Models/Sessions/SessionObserveParamsTest.cs +++ b/src/Stagehand.Tests/Models/Sessions/SessionObserveParamsTest.cs @@ -1080,6 +1080,8 @@ public void GenericModelConfigObjectValidationWorks() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionObserveParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; value.Validate(); @@ -1212,6 +1214,8 @@ public void GenericModelConfigObjectSerializationRoundtripWorks() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionObserveParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); @@ -4185,6 +4189,8 @@ public void FieldRoundtrip_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionObserveParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4192,6 +4198,11 @@ public void FieldRoundtrip_Works() string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum< + string, + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > expectedOpenAIEndpointFormat = + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat; ApiEnum< string, SessionObserveParamsOptionsModelGenericModelConfigObjectProvider @@ -4209,6 +4220,7 @@ public void FieldRoundtrip_Works() Assert.Equal(value, model.Headers[item.Key]); } + Assert.Equal(expectedOpenAIEndpointFormat, model.OpenAIEndpointFormat); Assert.Equal(expectedProvider, model.Provider); } @@ -4221,6 +4233,8 @@ public void SerializationRoundtrip_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionObserveParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4243,6 +4257,8 @@ public void FieldRoundtripThroughSerialization_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionObserveParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4258,6 +4274,11 @@ public void FieldRoundtripThroughSerialization_Works() string expectedApiKey = "sk-some-openai-api-key"; string expectedBaseUrl = "https://api.openai.com/v1"; Dictionary expectedHeaders = new() { { "foo", "string" } }; + ApiEnum< + string, + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > expectedOpenAIEndpointFormat = + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat; ApiEnum< string, SessionObserveParamsOptionsModelGenericModelConfigObjectProvider @@ -4275,6 +4296,7 @@ public void FieldRoundtripThroughSerialization_Works() Assert.Equal(value, deserialized.Headers[item.Key]); } + Assert.Equal(expectedOpenAIEndpointFormat, deserialized.OpenAIEndpointFormat); Assert.Equal(expectedProvider, deserialized.Provider); } @@ -4287,6 +4309,8 @@ public void Validation_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionObserveParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4307,6 +4331,8 @@ public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.OpenAIEndpointFormat); + Assert.False(model.RawData.ContainsKey("openaiEndpointFormat")); Assert.Null(model.Provider); Assert.False(model.RawData.ContainsKey("provider")); } @@ -4333,6 +4359,7 @@ public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() ApiKey = null, BaseUrl = null, Headers = null, + OpenAIEndpointFormat = null, Provider = null, }; @@ -4342,6 +4369,8 @@ public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() Assert.False(model.RawData.ContainsKey("baseURL")); Assert.Null(model.Headers); Assert.False(model.RawData.ContainsKey("headers")); + Assert.Null(model.OpenAIEndpointFormat); + Assert.False(model.RawData.ContainsKey("openaiEndpointFormat")); Assert.Null(model.Provider); Assert.False(model.RawData.ContainsKey("provider")); } @@ -4357,6 +4386,7 @@ public void OptionalNonNullablePropertiesSetToNullValidation_Works() ApiKey = null, BaseUrl = null, Headers = null, + OpenAIEndpointFormat = null, Provider = null, }; @@ -4372,6 +4402,8 @@ public void CopyConstructor_Works() ApiKey = "sk-some-openai-api-key", BaseUrl = "https://api.openai.com/v1", Headers = new Dictionary() { { "foo", "string" } }, + OpenAIEndpointFormat = + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, Provider = SessionObserveParamsOptionsModelGenericModelConfigObjectProvider.OpenAI, }; @@ -4381,6 +4413,87 @@ public void CopyConstructor_Works() } } +public class SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormatTest + : TestBase +{ + [Theory] + [InlineData( + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Responses + )] + [InlineData(SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat)] + public void Validation_Works( + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > value = rawValue; + value.Validate(); + } + + [Fact] + public void InvalidEnumValidationThrows_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + + Assert.NotNull(value); + Assert.Throws(() => value.Validate()); + } + + [Theory] + [InlineData( + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Responses + )] + [InlineData(SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat)] + public void SerializationRoundtrip_Works( + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat rawValue + ) + { + // force implicit conversion because Theory can't do that for us + ApiEnum< + string, + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > value = rawValue; + + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } + + [Fact] + public void InvalidEnumSerializationRoundtrip_Works() + { + var value = JsonSerializer.Deserialize< + ApiEnum< + string, + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > + >(JsonSerializer.SerializeToElement("invalid value"), ModelBase.SerializerOptions); + string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); + var deserialized = JsonSerializer.Deserialize< + ApiEnum< + string, + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > + >(json, ModelBase.SerializerOptions); + + Assert.Equal(value, deserialized); + } +} + public class SessionObserveParamsOptionsModelGenericModelConfigObjectProviderTest : TestBase { [Theory] diff --git a/src/Stagehand/Core/ModelBase.cs b/src/Stagehand/Core/ModelBase.cs index 9307f4d..dff9424 100644 --- a/src/Stagehand/Core/ModelBase.cs +++ b/src/Stagehand/Core/ModelBase.cs @@ -22,10 +22,12 @@ protected ModelBase(ModelBase modelBase) { new FrozenDictionaryConverterFactory(), new ApiEnumConverter(), + new ApiEnumConverter(), new ApiEnumConverter(), new ApiEnumConverter(), new ApiEnumConverter(), new ApiEnumConverter(), + new ApiEnumConverter(), new ApiEnumConverter(), new ApiEnumConverter(), new ApiEnumConverter(), @@ -33,12 +35,20 @@ protected ModelBase(ModelBase modelBase) string, ExecutionModelVertexModelConfigObjectAuthCredentialsType >(), + new ApiEnumConverter< + string, + ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat + >(), new ApiEnumConverter(), new ApiEnumConverter(), new ApiEnumConverter< string, AgentConfigModelVertexModelConfigObjectAuthCredentialsType >(), + new ApiEnumConverter< + string, + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat + >(), new ApiEnumConverter(), new ApiEnumConverter(), new ApiEnumConverter(), @@ -46,6 +56,10 @@ protected ModelBase(ModelBase modelBase) string, SessionExtractParamsOptionsModelVertexModelConfigObjectAuthCredentialsType >(), + new ApiEnumConverter< + string, + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + >(), new ApiEnumConverter< string, SessionExtractParamsOptionsModelGenericModelConfigObjectProvider @@ -57,6 +71,10 @@ protected ModelBase(ModelBase modelBase) string, SessionObserveParamsOptionsModelVertexModelConfigObjectAuthCredentialsType >(), + new ApiEnumConverter< + string, + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + >(), new ApiEnumConverter< string, SessionObserveParamsOptionsModelGenericModelConfigObjectProvider diff --git a/src/Stagehand/Models/Sessions/ModelConfig.cs b/src/Stagehand/Models/Sessions/ModelConfig.cs index 70ec95f..26c592b 100644 --- a/src/Stagehand/Models/Sessions/ModelConfig.cs +++ b/src/Stagehand/Models/Sessions/ModelConfig.cs @@ -2635,6 +2635,33 @@ public IReadOnlyDictionary? Headers } } + /// + /// Wire format used by an OpenAI-compatible endpoint. Defaults to the Responses + /// API; use chat for Chat Completions-only endpoints. + /// + public ApiEnum< + string, + ModelConfigGenericModelConfigObjectOpenAIEndpointFormat + >? OpenAIEndpointFormat + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass< + ApiEnum + >("openaiEndpointFormat"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("openaiEndpointFormat", value); + } + } + /// /// AI provider for the model (or provide a baseURL endpoint instead) /// @@ -2665,6 +2692,7 @@ public override void Validate() _ = this.ApiKey; _ = this.BaseUrl; _ = this.Headers; + this.OpenAIEndpointFormat?.Validate(); this.Provider?.Validate(); } @@ -2715,6 +2743,55 @@ IReadOnlyDictionary rawData ) => ModelConfigGenericModelConfigObject.FromRawUnchecked(rawData); } +/// +/// Wire format used by an OpenAI-compatible endpoint. Defaults to the Responses API; +/// use chat for Chat Completions-only endpoints. +/// +[JsonConverter(typeof(ModelConfigGenericModelConfigObjectOpenAIEndpointFormatConverter))] +public enum ModelConfigGenericModelConfigObjectOpenAIEndpointFormat +{ + Responses, + Chat, +} + +sealed class ModelConfigGenericModelConfigObjectOpenAIEndpointFormatConverter + : JsonConverter +{ + public override ModelConfigGenericModelConfigObjectOpenAIEndpointFormat Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "responses" => ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Responses, + "chat" => ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Chat, + _ => (ModelConfigGenericModelConfigObjectOpenAIEndpointFormat)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ModelConfigGenericModelConfigObjectOpenAIEndpointFormat value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Responses => "responses", + ModelConfigGenericModelConfigObjectOpenAIEndpointFormat.Chat => "chat", + _ => throw new StagehandInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + /// /// AI provider for the model (or provide a baseURL endpoint instead) /// diff --git a/src/Stagehand/Models/Sessions/SessionActParams.cs b/src/Stagehand/Models/Sessions/SessionActParams.cs index 6a6906d..1560193 100644 --- a/src/Stagehand/Models/Sessions/SessionActParams.cs +++ b/src/Stagehand/Models/Sessions/SessionActParams.cs @@ -3112,6 +3112,30 @@ public IReadOnlyDictionary? Headers } } + /// + /// Wire format used by an OpenAI-compatible endpoint. Defaults to the Responses + /// API; use chat for Chat Completions-only endpoints. + /// + public ApiEnum? OpenAIEndpointFormat + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass>( + "openaiEndpointFormat" + ); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("openaiEndpointFormat", value); + } + } + /// /// AI provider for the model (or provide a baseURL endpoint instead) /// @@ -3140,6 +3164,7 @@ public override void Validate() _ = this.ApiKey; _ = this.BaseUrl; _ = this.Headers; + this.OpenAIEndpointFormat?.Validate(); this.Provider?.Validate(); } @@ -3188,6 +3213,54 @@ IReadOnlyDictionary rawData ) => GenericModelConfigObject.FromRawUnchecked(rawData); } +/// +/// Wire format used by an OpenAI-compatible endpoint. Defaults to the Responses API; +/// use chat for Chat Completions-only endpoints. +/// +[JsonConverter(typeof(OpenAIEndpointFormatConverter))] +public enum OpenAIEndpointFormat +{ + Responses, + Chat, +} + +sealed class OpenAIEndpointFormatConverter : JsonConverter +{ + public override OpenAIEndpointFormat Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "responses" => OpenAIEndpointFormat.Responses, + "chat" => OpenAIEndpointFormat.Chat, + _ => (OpenAIEndpointFormat)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + OpenAIEndpointFormat value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + OpenAIEndpointFormat.Responses => "responses", + OpenAIEndpointFormat.Chat => "chat", + _ => throw new StagehandInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + /// /// AI provider for the model (or provide a baseURL endpoint instead) /// diff --git a/src/Stagehand/Models/Sessions/SessionExecuteParams.cs b/src/Stagehand/Models/Sessions/SessionExecuteParams.cs index d8de35d..e64af8d 100644 --- a/src/Stagehand/Models/Sessions/SessionExecuteParams.cs +++ b/src/Stagehand/Models/Sessions/SessionExecuteParams.cs @@ -3114,6 +3114,33 @@ public IReadOnlyDictionary? Headers } } + /// + /// Wire format used by an OpenAI-compatible endpoint. Defaults to the Responses + /// API; use chat for Chat Completions-only endpoints. + /// + public ApiEnum< + string, + ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat + >? OpenAIEndpointFormat + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass< + ApiEnum + >("openaiEndpointFormat"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("openaiEndpointFormat", value); + } + } + /// /// AI provider for the model (or provide a baseURL endpoint instead) /// @@ -3144,6 +3171,7 @@ public override void Validate() _ = this.ApiKey; _ = this.BaseUrl; _ = this.Headers; + this.OpenAIEndpointFormat?.Validate(); this.Provider?.Validate(); } @@ -3195,6 +3223,55 @@ IReadOnlyDictionary rawData ) => ExecutionModelGenericModelConfigObject.FromRawUnchecked(rawData); } +/// +/// Wire format used by an OpenAI-compatible endpoint. Defaults to the Responses API; +/// use chat for Chat Completions-only endpoints. +/// +[JsonConverter(typeof(ExecutionModelGenericModelConfigObjectOpenAIEndpointFormatConverter))] +public enum ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat +{ + Responses, + Chat, +} + +sealed class ExecutionModelGenericModelConfigObjectOpenAIEndpointFormatConverter + : JsonConverter +{ + public override ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "responses" => ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Responses, + "chat" => ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, + _ => (ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Responses => "responses", + ExecutionModelGenericModelConfigObjectOpenAIEndpointFormat.Chat => "chat", + _ => throw new StagehandInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + /// /// AI provider for the model (or provide a baseURL endpoint instead) /// @@ -6020,6 +6097,33 @@ public IReadOnlyDictionary? Headers } } + /// + /// Wire format used by an OpenAI-compatible endpoint. Defaults to the Responses + /// API; use chat for Chat Completions-only endpoints. + /// + public ApiEnum< + string, + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat + >? OpenAIEndpointFormat + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass< + ApiEnum + >("openaiEndpointFormat"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("openaiEndpointFormat", value); + } + } + /// /// AI provider for the model (or provide a baseURL endpoint instead) /// @@ -6050,6 +6154,7 @@ public override void Validate() _ = this.ApiKey; _ = this.BaseUrl; _ = this.Headers; + this.OpenAIEndpointFormat?.Validate(); this.Provider?.Validate(); } @@ -6103,6 +6208,56 @@ IReadOnlyDictionary rawData ) => AgentConfigModelGenericModelConfigObject.FromRawUnchecked(rawData); } +/// +/// Wire format used by an OpenAI-compatible endpoint. Defaults to the Responses API; +/// use chat for Chat Completions-only endpoints. +/// +[JsonConverter(typeof(AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormatConverter))] +public enum AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat +{ + Responses, + Chat, +} + +sealed class AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormatConverter + : JsonConverter +{ + public override AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "responses" => AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Responses, + "chat" => AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, + _ => (AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Responses => + "responses", + AgentConfigModelGenericModelConfigObjectOpenAIEndpointFormat.Chat => "chat", + _ => throw new StagehandInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + /// /// AI provider for the model (or provide a baseURL endpoint instead) /// diff --git a/src/Stagehand/Models/Sessions/SessionExtractParams.cs b/src/Stagehand/Models/Sessions/SessionExtractParams.cs index 8d287ad..f5a7565 100644 --- a/src/Stagehand/Models/Sessions/SessionExtractParams.cs +++ b/src/Stagehand/Models/Sessions/SessionExtractParams.cs @@ -3201,6 +3201,36 @@ public IReadOnlyDictionary? Headers } } + /// + /// Wire format used by an OpenAI-compatible endpoint. Defaults to the Responses + /// API; use chat for Chat Completions-only endpoints. + /// + public ApiEnum< + string, + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + >? OpenAIEndpointFormat + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass< + ApiEnum< + string, + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > + >("openaiEndpointFormat"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("openaiEndpointFormat", value); + } + } + /// /// AI provider for the model (or provide a baseURL endpoint instead) /// @@ -3234,6 +3264,7 @@ public override void Validate() _ = this.ApiKey; _ = this.BaseUrl; _ = this.Headers; + this.OpenAIEndpointFormat?.Validate(); this.Provider?.Validate(); } @@ -3289,6 +3320,61 @@ IReadOnlyDictionary rawData ) => SessionExtractParamsOptionsModelGenericModelConfigObject.FromRawUnchecked(rawData); } +/// +/// Wire format used by an OpenAI-compatible endpoint. Defaults to the Responses API; +/// use chat for Chat Completions-only endpoints. +/// +[JsonConverter( + typeof(SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormatConverter) +)] +public enum SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat +{ + Responses, + Chat, +} + +sealed class SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormatConverter + : JsonConverter +{ + public override SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "responses" => + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Responses, + "chat" => + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, + _ => (SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Responses => + "responses", + SessionExtractParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat => + "chat", + _ => throw new StagehandInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + /// /// AI provider for the model (or provide a baseURL endpoint instead) /// diff --git a/src/Stagehand/Models/Sessions/SessionObserveParams.cs b/src/Stagehand/Models/Sessions/SessionObserveParams.cs index 0185bc6..a9b33fa 100644 --- a/src/Stagehand/Models/Sessions/SessionObserveParams.cs +++ b/src/Stagehand/Models/Sessions/SessionObserveParams.cs @@ -3187,6 +3187,36 @@ public IReadOnlyDictionary? Headers } } + /// + /// Wire format used by an OpenAI-compatible endpoint. Defaults to the Responses + /// API; use chat for Chat Completions-only endpoints. + /// + public ApiEnum< + string, + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + >? OpenAIEndpointFormat + { + get + { + this._rawData.Freeze(); + return this._rawData.GetNullableClass< + ApiEnum< + string, + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat + > + >("openaiEndpointFormat"); + } + init + { + if (value == null) + { + return; + } + + this._rawData.Set("openaiEndpointFormat", value); + } + } + /// /// AI provider for the model (or provide a baseURL endpoint instead) /// @@ -3220,6 +3250,7 @@ public override void Validate() _ = this.ApiKey; _ = this.BaseUrl; _ = this.Headers; + this.OpenAIEndpointFormat?.Validate(); this.Provider?.Validate(); } @@ -3275,6 +3306,61 @@ IReadOnlyDictionary rawData ) => SessionObserveParamsOptionsModelGenericModelConfigObject.FromRawUnchecked(rawData); } +/// +/// Wire format used by an OpenAI-compatible endpoint. Defaults to the Responses API; +/// use chat for Chat Completions-only endpoints. +/// +[JsonConverter( + typeof(SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormatConverter) +)] +public enum SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat +{ + Responses, + Chat, +} + +sealed class SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormatConverter + : JsonConverter +{ + public override SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat Read( + ref Utf8JsonReader reader, + System::Type typeToConvert, + JsonSerializerOptions options + ) + { + return JsonSerializer.Deserialize(ref reader, options) switch + { + "responses" => + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Responses, + "chat" => + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat, + _ => (SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat)(-1), + }; + } + + public override void Write( + Utf8JsonWriter writer, + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat value, + JsonSerializerOptions options + ) + { + JsonSerializer.Serialize( + writer, + value switch + { + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Responses => + "responses", + SessionObserveParamsOptionsModelGenericModelConfigObjectOpenAIEndpointFormat.Chat => + "chat", + _ => throw new StagehandInvalidDataException( + string.Format("Invalid value '{0}' in {1}", value, nameof(value)) + ), + }, + options + ); + } +} + /// /// AI provider for the model (or provide a baseURL endpoint instead) /// From 0d81242a3cdd1980f72b98f4758be0e11b21583e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 25 Jul 2026 02:00:32 +0000 Subject: [PATCH 5/6] fix(client): tolerate JSON null in required untyped fields and prefer more specific union variants Also corrects date-time formatting in generated URL test expectations. --- .../Core/JsonDictionaryTest.cs | 37 ++++++++++++++++++ .../Core/MultipartJsonDictionaryTest.cs | 38 +++++++++++++++++++ src/Stagehand/Core/JsonDictionary.cs | 16 ++++++++ src/Stagehand/Core/MultipartJsonDictionary.cs | 16 ++++++++ .../Models/Sessions/SessionExecuteResponse.cs | 2 +- .../Models/Sessions/SessionExtractResponse.cs | 2 +- .../Sessions/SessionNavigateResponse.cs | 2 +- 7 files changed, 110 insertions(+), 3 deletions(-) diff --git a/src/Stagehand.Tests/Core/JsonDictionaryTest.cs b/src/Stagehand.Tests/Core/JsonDictionaryTest.cs index 85ec872..c6de93d 100644 --- a/src/Stagehand.Tests/Core/JsonDictionaryTest.cs +++ b/src/Stagehand.Tests/Core/JsonDictionaryTest.cs @@ -206,6 +206,43 @@ public void GetNotNullStruct_ThrowsWhenTypeInvalid() Assert.Contains("'text' must be of type", exception.Message); } + [Fact] + public void GetNotAbsentElement_ReturnsValue() + { + var dict = new JsonDictionary(); + dict.Set("age", 30); + + var age = dict.GetNotAbsentElement("age"); + + Assert.Equal(30, age.GetInt32()); + } + + [Fact] + public void GetNotAbsentElement_ThrowsWhenKeyAbsent() + { + var dict = new JsonDictionary(); + + var exception = Assert.Throws(() => + dict.GetNotAbsentElement("missing") + ); + Assert.Contains("'missing' cannot be absent", exception.Message); + } + + [Fact] + public void GetNotAbsentElement_ReturnsNullElementWhenValueIsNull() + { + var dict = new JsonDictionary( + new Dictionary + { + ["nullable"] = JsonSerializer.SerializeToElement(null), + } + ); + + var element = dict.GetNotAbsentElement("nullable"); + + Assert.Equal(JsonValueKind.Null, element.ValueKind); + } + [Fact] public void GetNullableClass_ReturnsValueWhenPresent() { diff --git a/src/Stagehand.Tests/Core/MultipartJsonDictionaryTest.cs b/src/Stagehand.Tests/Core/MultipartJsonDictionaryTest.cs index b447201..6be3c55 100644 --- a/src/Stagehand.Tests/Core/MultipartJsonDictionaryTest.cs +++ b/src/Stagehand.Tests/Core/MultipartJsonDictionaryTest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Frozen; using System.Collections.Generic; +using System.Text.Json; using Stagehand.Core; using Stagehand.Exceptions; @@ -205,6 +206,43 @@ public void GetNotNullStruct_ThrowsWhenTypeInvalid() Assert.Contains("'text' must be of type", exception.Message); } + [Fact] + public void GetNotAbsentElement_ReturnsValue() + { + var dict = new MultipartJsonDictionary(); + dict.Set("age", 30); + + var age = dict.GetNotAbsentElement("age"); + + Assert.Equal(30, age.GetInt32()); + } + + [Fact] + public void GetNotAbsentElement_ThrowsWhenKeyAbsent() + { + var dict = new MultipartJsonDictionary(); + + var exception = Assert.Throws(() => + dict.GetNotAbsentElement("missing") + ); + Assert.Contains("'missing' cannot be absent", exception.Message); + } + + [Fact] + public void GetNotAbsentElement_ReturnsNullElementWhenValueIsNull() + { + var dict = new MultipartJsonDictionary( + new Dictionary + { + ["nullable"] = MultipartJsonSerializer.SerializeToElement(null), + } + ); + + var element = dict.GetNotAbsentElement("nullable"); + + Assert.Equal(JsonValueKind.Null, element.ValueKind); + } + [Fact] public void GetNullableClass_ReturnsValueWhenPresent() { diff --git a/src/Stagehand/Core/JsonDictionary.cs b/src/Stagehand/Core/JsonDictionary.cs index 5307bd8..9e76c4a 100644 --- a/src/Stagehand/Core/JsonDictionary.cs +++ b/src/Stagehand/Core/JsonDictionary.cs @@ -149,6 +149,22 @@ public T GetNotNullStruct(string key) return deserialized; } + /// + /// Gets the raw JSON element for a key that must be present, without rejecting JSON null. + /// + /// Used for values of unknown type, which can be any JSON value including null. A JSON + /// null is returned as a whose ValueKind is + /// Null. + /// + public JsonElement GetNotAbsentElement(string key) + { + if (!_rawData.TryGetValue(key, out JsonElement element)) + { + throw new StagehandInvalidDataException($"'{key}' cannot be absent"); + } + return element; + } + public override string ToString() => JsonSerializer.Serialize( FriendlyJsonPrinter.PrintValue(this._rawData), diff --git a/src/Stagehand/Core/MultipartJsonDictionary.cs b/src/Stagehand/Core/MultipartJsonDictionary.cs index ca82816..30c28c7 100644 --- a/src/Stagehand/Core/MultipartJsonDictionary.cs +++ b/src/Stagehand/Core/MultipartJsonDictionary.cs @@ -152,6 +152,22 @@ public T GetNotNullStruct(string key) return deserialized; } + /// + /// Gets the raw JSON element for a key that must be present, without rejecting JSON null. + /// + /// Used for values of unknown type, which can be any JSON value including null. A JSON + /// null is returned as a whose ValueKind is + /// Null. + /// + public JsonElement GetNotAbsentElement(string key) + { + if (!_rawData.TryGetValue(key, out MultipartJsonElement element)) + { + throw new StagehandInvalidDataException($"'{key}' cannot be absent"); + } + return element.Json; + } + public override string ToString() => JsonSerializer.Serialize( FriendlyJsonPrinter.PrintValue(this._rawData), diff --git a/src/Stagehand/Models/Sessions/SessionExecuteResponse.cs b/src/Stagehand/Models/Sessions/SessionExecuteResponse.cs index bad73f3..c7e512d 100644 --- a/src/Stagehand/Models/Sessions/SessionExecuteResponse.cs +++ b/src/Stagehand/Models/Sessions/SessionExecuteResponse.cs @@ -676,7 +676,7 @@ public required JsonElement Entry get { this._rawData.Freeze(); - return this._rawData.GetNotNullStruct("entry"); + return this._rawData.GetNotAbsentElement("entry"); } init { this._rawData.Set("entry", value); } } diff --git a/src/Stagehand/Models/Sessions/SessionExtractResponse.cs b/src/Stagehand/Models/Sessions/SessionExtractResponse.cs index 8547202..1d80f4d 100644 --- a/src/Stagehand/Models/Sessions/SessionExtractResponse.cs +++ b/src/Stagehand/Models/Sessions/SessionExtractResponse.cs @@ -91,7 +91,7 @@ public required JsonElement Result get { this._rawData.Freeze(); - return this._rawData.GetNotNullStruct("result"); + return this._rawData.GetNotAbsentElement("result"); } init { this._rawData.Set("result", value); } } diff --git a/src/Stagehand/Models/Sessions/SessionNavigateResponse.cs b/src/Stagehand/Models/Sessions/SessionNavigateResponse.cs index 8ff8cd8..6c1d3b6 100644 --- a/src/Stagehand/Models/Sessions/SessionNavigateResponse.cs +++ b/src/Stagehand/Models/Sessions/SessionNavigateResponse.cs @@ -91,7 +91,7 @@ public required JsonElement Result get { this._rawData.Freeze(); - return this._rawData.GetNotNullStruct("result"); + return this._rawData.GetNotAbsentElement("result"); } init { this._rawData.Set("result", value); } } From 06de8bf30afa35ffead7969df2083c3d3ab36450 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 25 Jul 2026 02:00:55 +0000 Subject: [PATCH 6/6] release: 3.22.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 16 ++++++++++++++++ src/Stagehand/Stagehand.csproj | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index eba8a04..1887bd5 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.21.0" + ".": "3.22.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 0350a1f..a66fffa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,21 @@ # Changelog +## 3.22.0 (2026-07-25) + +Full Changelog: [v3.21.0...v3.22.0](https://github.com/browserbase/stagehand-net/compare/v3.21.0...v3.22.0) + +### Features + +* [STG-2090] Add Azure Entra model auth support ([889f962](https://github.com/browserbase/stagehand-net/commit/889f962499019bbe14fbb29e2d5bf6afdf096a99)) +* **server-v3:** expose OpenAI endpoint format ([eb515f8](https://github.com/browserbase/stagehand-net/commit/eb515f8aa3a8d6d508cc5e3d3c4f8e598744f57d)) +* **stlc:** configurable CI runner and private-production-repo support in workflow templates ([21b8d30](https://github.com/browserbase/stagehand-net/commit/21b8d30f5b2d75636d77521c9ebe255be396a756)) + + +### Bug Fixes + +* **client:** tolerate JSON null in required untyped fields and prefer more specific union variants ([0d81242](https://github.com/browserbase/stagehand-net/commit/0d81242a3cdd1980f72b98f4758be0e11b21583e)) +* **csharp:** resolve ambiguity in parsing query strings ([6a57880](https://github.com/browserbase/stagehand-net/commit/6a57880b0ecfbe79c5acc5e5a942df3d19494715)) + ## 3.21.0 (2026-05-29) Full Changelog: [v3.20.0...v3.21.0](https://github.com/browserbase/stagehand-net/compare/v3.20.0...v3.21.0) diff --git a/src/Stagehand/Stagehand.csproj b/src/Stagehand/Stagehand.csproj index 0acca9d..a2bd548 100644 --- a/src/Stagehand/Stagehand.csproj +++ b/src/Stagehand/Stagehand.csproj @@ -3,7 +3,7 @@ Stagehand C# Stagehand - 3.21.0 + 3.22.0 The official .NET library for the Stagehand API. Library README.md