From 069ec002a69093d4daa9b8c11114ca34bc01c95d Mon Sep 17 00:00:00 2001 From: Artem Repko Date: Sat, 14 Jun 2025 18:43:22 +0200 Subject: [PATCH 1/9] Add support for JSON Schema $defs, definitions, $ref, and anyOf in PropertyDefinition This PR extends PropertyDefinition to support additional JSON Schema draft-07 elements: $defs (for schema definitions) definitions $ref (schema references) anyOf (combining subschemas) These additions improve compatibility with more complex JSON Schema structures. --- .../SharedModels/FunctionParameters.cs | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs b/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs index 743af244..c3aa6aaa 100644 --- a/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs +++ b/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs @@ -1,4 +1,4 @@ -using System.Text.Json.Serialization; +using System.Text.Json.Serialization; namespace Betalgo.Ranul.OpenAI.ObjectModels.SharedModels; @@ -77,6 +77,33 @@ public enum FunctionObjectTypes /// [JsonPropertyName("items")] public PropertyDefinition? Items { get; set; } + + /// + /// Definitions of schemas (draft-07 specification). + /// For more details, see https://json-schema.org/understanding-json-schema/structuring#defs + /// + [JsonPropertyName("$defs")] + public IDictionary? Defs { get; set; } + + /// + /// Definitions of schemas (draft-07 specification). + /// + [JsonPropertyName("definitions")] + public IDictionary? Definitions { get; set; } + + /// + /// Reference to another schema definition. + /// For more details, see https://json-schema.org/understanding-json-schema/structuring#dollarref + /// + [JsonPropertyName("$ref")] + public string? Ref { get; set; } + + /// + /// To validate against anyOf, the given data must be valid against any (one or more) of the given subschemas. + /// For more details, see https://json-schema.org/understanding-json-schema/reference/combining#anyOf + /// + [JsonPropertyName("anyOf")] + public IList? AnyOf { get; set; } public static PropertyDefinition DefineArray(PropertyDefinition? arrayItems = null) { @@ -174,4 +201,4 @@ public static string ConvertTypeToString(FunctionObjectTypes type) _ => throw new ArgumentOutOfRangeException(nameof(type), $"Unknown type: {type}") }; } -} \ No newline at end of file +} From 76ade80eb31bf6fe67d655ed0adc4e19eecd5016 Mon Sep 17 00:00:00 2001 From: Artem Repko Date: Sat, 14 Jun 2025 18:51:51 +0200 Subject: [PATCH 2/9] Updated documentations for $defs --- OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs b/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs index c3aa6aaa..68cd73d0 100644 --- a/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs +++ b/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs @@ -79,7 +79,7 @@ public enum FunctionObjectTypes public PropertyDefinition? Items { get; set; } /// - /// Definitions of schemas (draft-07 specification). + /// Definitions of schemas (2020-12 and newer specifications). /// For more details, see https://json-schema.org/understanding-json-schema/structuring#defs /// [JsonPropertyName("$defs")] From 200af8285e853a0922dbbabb3c22ca8a564fb36d Mon Sep 17 00:00:00 2001 From: Artem Repko Date: Sun, 15 Jun 2025 14:34:03 +0200 Subject: [PATCH 3/9] Add support for json schemas: const, title, minimum, maximum, oneOf keywords --- .../SharedModels/FunctionParameters.cs | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs b/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs index 68cd73d0..b316667b 100644 --- a/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs +++ b/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs @@ -23,7 +23,14 @@ public enum FunctionObjectTypes /// Required. Function parameter object type. Default value is "object". /// [JsonPropertyName("type")] - public string Type { get; set; } = "object"; + public string? Type { get; set; } + + /// + /// An instance validates successfully against this keyword if its value is equal to the value of the keyword + /// https://json-schema.org/draft/2020-12/json-schema-validation#name-const + /// + [JsonPropertyName("const")] + public string? Constant { get; set; } /// /// Optional. List of "function arguments", as a dictionary that maps from argument name @@ -45,7 +52,15 @@ public enum FunctionObjectTypes public bool? AdditionalProperties { get; set; } /// - /// Optional. Argument description. + /// Optional. Title of the schema. + /// https://json-schema.org/draft/2020-12/json-schema-validation#name-title-and-description + /// + [JsonPropertyName("title")] + public string? Title { get; set; } + + /// + /// Optional. Description of the schema. + /// https://json-schema.org/draft/2020-12/json-schema-validation#name-title-and-description /// [JsonPropertyName("description")] public string? Description { get; set; } @@ -69,6 +84,20 @@ public enum FunctionObjectTypes /// [JsonPropertyName("maxProperties")] public int? MaxProperties { get; set; } + + /// + /// The value of "minimum" MUST be a number, representing an inclusive lower limit for a numeric instance. + /// https://json-schema.org/draft/2020-12/json-schema-validation#name-minimum + /// + [JsonPropertyName("minimum")] + public float? Minimum { get; set; } + + /// + /// The value of "maximum" MUST be a number, representing an inclusive upper limit for a numeric instance. + /// https://json-schema.org/draft/2020-12/json-schema-validation#name-maximum + /// + [JsonPropertyName("maximum")] + public float? Maximum { get; set; } /// /// If type is "array", this specifies the element type for all items in the array. @@ -104,6 +133,13 @@ public enum FunctionObjectTypes /// [JsonPropertyName("anyOf")] public IList? AnyOf { get; set; } + + /// + /// To validate against oneOf, the given data must be valid against exactly one of the given subschemas. + /// For more details, see https://json-schema.org/understanding-json-schema/reference/combining#oneOf + /// + [JsonPropertyName("oneOf")] + public IList? OneOf { get; set; } public static PropertyDefinition DefineArray(PropertyDefinition? arrayItems = null) { From e492049630798f2e14f979c9c8ba09ceb67d5a28 Mon Sep 17 00:00:00 2001 From: "A.Repko" Date: Tue, 17 Jun 2025 16:30:15 +0200 Subject: [PATCH 4/9] Update project metadata and add new JSON Schema properties: multipleOf, exclusiveMinimum, exclusiveMaximum, format, pattern, minItems, maxItems --- .../SharedModels/FunctionParameters.cs | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs b/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs index b316667b..d57b9822 100644 --- a/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs +++ b/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs @@ -85,6 +85,14 @@ public enum FunctionObjectTypes [JsonPropertyName("maxProperties")] public int? MaxProperties { get; set; } + /// + /// The value of "multipleOf" MUST be a number, strictly greater than 0. + /// A numeric instance is valid only if division by this keyword's value results in an integer. + /// https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.6.2.1 + /// + [JsonPropertyName("multipleOf")] + public int? MultipleOf { get; set; } + /// /// The value of "minimum" MUST be a number, representing an inclusive lower limit for a numeric instance. /// https://json-schema.org/draft/2020-12/json-schema-validation#name-minimum @@ -92,12 +100,58 @@ public enum FunctionObjectTypes [JsonPropertyName("minimum")] public float? Minimum { get; set; } + /// + /// The value of "exclusiveMinimum" MUST be a number, representing an exclusive lower limit for a numeric + /// instance. If the instance is a number, then the instance is valid only if it has a value strictly greater + /// than (not equal to) "exclusiveMinimum". + /// https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.6.2.5 + /// + [JsonPropertyName("exclusiveMinimum")] + public float? ExclusiveMinimum { get; set; } + /// /// The value of "maximum" MUST be a number, representing an inclusive upper limit for a numeric instance. /// https://json-schema.org/draft/2020-12/json-schema-validation#name-maximum /// [JsonPropertyName("maximum")] public float? Maximum { get; set; } + + /// + /// The value of "exclusiveMaximum" MUST be a number, representing an exclusive upper limit for a numeric + /// instance. If the instance is a number, then the instance is valid only if it has a value strictly less than + /// (not equal to) "exclusiveMaximum". + /// https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.6.2.3 + /// + [JsonPropertyName("exclusiveMaximum")] + public float? ExclusiveMaximum { get; set; } + + /// + /// Predefined formats for strings. Currently supported: + /// date-time, time, date, duration, email, hostname, ipv4, ipv6, uuid + /// + [JsonPropertyName("format")] + public string? Format { get; set; } + + /// + /// A regular expression that the string must match. + /// https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#pattern + /// + [JsonPropertyName("pattern")] + public string? Pattern { get; set; } + + /// + /// The array must have at least this many items. + /// https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.6.4.2 + /// + [JsonPropertyName("minItems")] + public int? MinItems { get; set; } + + /// + /// The array must have at most this many items. + /// https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.6.4.4 + /// + [JsonPropertyName("maxItems")] + public int? MaxItems { get; set; } /// /// If type is "array", this specifies the element type for all items in the array. From 477569b12881ce592cc7778a936548e8a85c7c56 Mon Sep 17 00:00:00 2001 From: "A.Repko" Date: Wed, 18 Jun 2025 16:15:36 +0200 Subject: [PATCH 5/9] Update project metadata and add new JSON Schema properties: multipleOf - can be float --- OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj b/OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj index ebef2714..343a1c3f 100644 --- a/OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj +++ b/OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj @@ -9,18 +9,18 @@ https://openai.com/ Betalgo-Ranul-OpenAI-icon.png true - OpenAI SDK by Betalgo - 9.0.4 + Fork fo OpenAI SDK by Betalgo + 9.0.4.7 Tolga Kayhan, Betalgo Betalgo Up Ltd. - OpenAI .NET library by Betalgo Ranul + Fork for OpenAI .NET library by Betalgo Ranul .NET library for the OpenAI services by Betalgo Ranul https://github.com/betalgo/openai/ openAI,realtime,chatGPT,gpt-4, gpt-3,DALL·E,whisper,azureOpenAI,ai,betalgo,NLP,dalle,dall-e,OpenAI,OpenAi,openAi,azure - Betalgo.Ranul.OpenAI + Betalgo.Ranul.OpenAI.Fork Readme.md True - https://github.com/betalgo/openai.git + https://github.com/repko-artem/betalgo_openai_json_schemas_support.git git True MIT From aa9fb09df870a2220cd280ddbd377d17a7bcc0cf Mon Sep 17 00:00:00 2001 From: "A.Repko" Date: Wed, 18 Jun 2025 17:14:44 +0200 Subject: [PATCH 6/9] Update project metadata and add new JSON Schema properties: multipleOf - can be float --- OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs b/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs index d57b9822..ab06f566 100644 --- a/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs +++ b/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs @@ -20,7 +20,7 @@ public enum FunctionObjectTypes } /// - /// Required. Function parameter object type. Default value is "object". + /// Function parameter object type. Default value is "object". /// [JsonPropertyName("type")] public string? Type { get; set; } @@ -91,7 +91,7 @@ public enum FunctionObjectTypes /// https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-00#rfc.section.6.2.1 /// [JsonPropertyName("multipleOf")] - public int? MultipleOf { get; set; } + public float? MultipleOf { get; set; } /// /// The value of "minimum" MUST be a number, representing an inclusive lower limit for a numeric instance. From 9936f295d5190d04693ed6712eaf0ef693b3d3be Mon Sep 17 00:00:00 2001 From: "A.Repko" Date: Wed, 18 Jun 2025 18:29:06 +0200 Subject: [PATCH 7/9] Revert "Update project metadata and add new JSON Schema properties: multipleOf - can be float" This reverts commit 477569b12881ce592cc7778a936548e8a85c7c56. --- OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj b/OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj index 343a1c3f..ebef2714 100644 --- a/OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj +++ b/OpenAI.SDK/Betalgo.Ranul.OpenAI.csproj @@ -9,18 +9,18 @@ https://openai.com/ Betalgo-Ranul-OpenAI-icon.png true - Fork fo OpenAI SDK by Betalgo - 9.0.4.7 + OpenAI SDK by Betalgo + 9.0.4 Tolga Kayhan, Betalgo Betalgo Up Ltd. - Fork for OpenAI .NET library by Betalgo Ranul + OpenAI .NET library by Betalgo Ranul .NET library for the OpenAI services by Betalgo Ranul https://github.com/betalgo/openai/ openAI,realtime,chatGPT,gpt-4, gpt-3,DALL·E,whisper,azureOpenAI,ai,betalgo,NLP,dalle,dall-e,OpenAI,OpenAi,openAi,azure - Betalgo.Ranul.OpenAI.Fork + Betalgo.Ranul.OpenAI Readme.md True - https://github.com/repko-artem/betalgo_openai_json_schemas_support.git + https://github.com/betalgo/openai.git git True MIT From 162a613622e27b3139a4042393d74c8ee3e5fdb0 Mon Sep 17 00:00:00 2001 From: "A.Repko" Date: Sun, 6 Jul 2025 15:13:27 +0200 Subject: [PATCH 8/9] Update project metadata and add new JSON Schema properties: support array-like type of property to support optional props https://platform.openai.com/docs/guides/structured-outputs#all-fields-must-be-required --- OpenAI.SDK/ObjectModels/Converters.cs | 49 ++++++++++++++++++- .../SharedModels/FunctionParameters.cs | 20 +++++++- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/OpenAI.SDK/ObjectModels/Converters.cs b/OpenAI.SDK/ObjectModels/Converters.cs index 549a7050..8853a896 100644 --- a/OpenAI.SDK/ObjectModels/Converters.cs +++ b/OpenAI.SDK/ObjectModels/Converters.cs @@ -89,4 +89,51 @@ public override void Write(Utf8JsonWriter writer, AssistantsApiToolChoiceOneOfTy writer.WriteNullValue(); } } -} \ No newline at end of file +} + +public class SingleOrArrayToListConverter : JsonConverter> +{ + public override List? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { + switch (reader.TokenType) { + case JsonTokenType.String: + return [reader.GetString()]; + case JsonTokenType.StartArray: + { + var list = new List(); + while (reader.Read() && reader.TokenType != JsonTokenType.EndArray) { + switch (reader.TokenType) { + case JsonTokenType.String: + list.Add(reader.GetString()); + break; + case JsonTokenType.Null: + list.Add(null); + break; + default: + throw new JsonException($"Unexpected token in type array: {reader.TokenType}"); + } + } + return list; + } + default: + throw new JsonException($"Unexpected token parsing type: {reader.TokenType}"); + } + } + + public override void Write(Utf8JsonWriter writer, List? value, JsonSerializerOptions options) { + if (value == null || value.Count == 0) { + writer.WriteNullValue(); + } else if (value.Count == 1) { + writer.WriteStringValue(value[0]); + } else { + writer.WriteStartArray(); + foreach (var item in value) { + if (item == null) { + writer.WriteNullValue(); + } else { + writer.WriteStringValue(item); + } + } + writer.WriteEndArray(); + } + } +} diff --git a/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs b/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs index ab06f566..b86fd8e2 100644 --- a/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs +++ b/OpenAI.SDK/ObjectModels/SharedModels/FunctionParameters.cs @@ -20,10 +20,26 @@ public enum FunctionObjectTypes } /// - /// Function parameter object type. Default value is "object". + /// Property's type as a string. Only one: or should be set. + /// + [JsonIgnore] + public string? Type { + get => TypeList?.Count != 1 ? null : TypeList[0]; + set { + if (value == null) { + TypeList = null; + return; + } + TypeList = [value]; + } + } + + /// + /// Property's type as a list of strings. Only one: or should be set. /// [JsonPropertyName("type")] - public string? Type { get; set; } + [JsonConverter(typeof(SingleOrArrayToListConverter))] + public IList? TypeList { get; set; } /// /// An instance validates successfully against this keyword if its value is equal to the value of the keyword From ba5de8ff4c1b772370642d963451d285fb9bd69c Mon Sep 17 00:00:00 2001 From: "A.Repko" Date: Sun, 6 Jul 2025 15:40:26 +0200 Subject: [PATCH 9/9] Update project metadata and add new JSON Schema properties: support array-like type of property to support optional props https://platform.openai.com/docs/guides/structured-outputs#all-fields-must-be-required --- OpenAI.SDK/ObjectModels/Converters.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenAI.SDK/ObjectModels/Converters.cs b/OpenAI.SDK/ObjectModels/Converters.cs index 8853a896..cd9b2b36 100644 --- a/OpenAI.SDK/ObjectModels/Converters.cs +++ b/OpenAI.SDK/ObjectModels/Converters.cs @@ -91,9 +91,9 @@ public override void Write(Utf8JsonWriter writer, AssistantsApiToolChoiceOneOfTy } } -public class SingleOrArrayToListConverter : JsonConverter> +public class SingleOrArrayToListConverter : JsonConverter> { - public override List? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { + public override IList? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { switch (reader.TokenType) { case JsonTokenType.String: return [reader.GetString()]; @@ -119,7 +119,7 @@ public class SingleOrArrayToListConverter : JsonConverter> } } - public override void Write(Utf8JsonWriter writer, List? value, JsonSerializerOptions options) { + public override void Write(Utf8JsonWriter writer, IList? value, JsonSerializerOptions options) { if (value == null || value.Count == 0) { writer.WriteNullValue(); } else if (value.Count == 1) {