diff --git a/dotnet/samples/GettingStartedWithProcesses/Step04/SchemaGenerator.cs b/dotnet/samples/GettingStartedWithProcesses/Step04/SchemaGenerator.cs
index 89d6c99de731..5350e2c53d6e 100644
--- a/dotnet/samples/GettingStartedWithProcesses/Step04/SchemaGenerator.cs
+++ b/dotnet/samples/GettingStartedWithProcesses/Step04/SchemaGenerator.cs
@@ -1,10 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.
-using System.ComponentModel;
-using System.Reflection;
using System.Text.Json;
-using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
-using JsonSchemaMapper;
+using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
namespace Step04;
@@ -14,55 +11,18 @@ internal static class JsonSchemaGenerator
///
/// Wrapper for generating a JSON schema as string from a .NET type.
///
- public static string FromType()
+ public static string FromType()
{
JsonSerializerOptions options = new(JsonSerializerOptions.Default)
{
UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow,
};
- JsonSchemaMapperConfiguration config = new()
+ AIJsonSchemaCreateOptions config = new()
{
- TreatNullObliviousAsNonNullable = true,
- TransformSchemaNode = (context, schema) =>
- {
- // NOTE: This can be replaced with `IncludeAdditionalProperties = false` when upgraded to System.Json.Text 9.0.0
- if (context.TypeInfo.Type == typeof(SchemaType))
- {
- schema["additionalProperties"] = false;
- }
-
- // Determine if a type or property and extract the relevant attribute provider
- ICustomAttributeProvider? attributeProvider = context.PropertyInfo is not null
- ? context.PropertyInfo.AttributeProvider
- : context.TypeInfo.Type;
-
- // Look up any description attributes
- DescriptionAttribute? descriptionAttr = attributeProvider?
- .GetCustomAttributes(inherit: true)
- .Select(attr => attr as DescriptionAttribute)
- .FirstOrDefault(attr => attr is not null);
-
- // Apply description attribute to the generated schema
- if (descriptionAttr != null)
- {
- if (schema is not JsonObject jObj)
- {
- // Handle the case where the schema is a boolean
- JsonValueKind valueKind = schema.GetValueKind();
- schema = jObj = new JsonObject();
- if (valueKind is JsonValueKind.False)
- {
- jObj.Add("not", true);
- }
- }
-
- jObj["description"] = descriptionAttr.Description;
- }
-
- return schema;
- }
+ IncludeSchemaKeyword = false,
+ DisallowAdditionalProperties = true,
};
- return KernelJsonSchemaBuilder.Build(typeof(SchemaType), "Intent Result", config).AsJson();
+ return KernelJsonSchemaBuilder.Build(typeof(TSchemaType), "Intent Result", config).AsJson();
}
}
diff --git a/dotnet/src/Connectors/Connectors.Google.UnitTests/Core/Gemini/GeminiFunctionTests.cs b/dotnet/src/Connectors/Connectors.Google.UnitTests/Core/Gemini/GeminiFunctionTests.cs
index b6dc394e6e92..0ae1a254e6f4 100644
--- a/dotnet/src/Connectors/Connectors.Google.UnitTests/Core/Gemini/GeminiFunctionTests.cs
+++ b/dotnet/src/Connectors/Connectors.Google.UnitTests/Core/Gemini/GeminiFunctionTests.cs
@@ -95,8 +95,8 @@ public void ItCanConvertToFunctionDefinitionsWithParameterTypesAndReturnParamete
{ "type": "object",
"required": ["param1", "param2"],
"properties": {
- "param1": { "type": "string", "description": "String param 1" },
- "param2": { "type": "integer", "description": "Int param 2" } } }
+ "param1": { "description": "String param 1", "type": "string" },
+ "param2": { "description": "Int param 2" , "type": "integer"} } }
""";
KernelPlugin plugin = KernelPluginFactory.CreateFromFunctions("Tests", new[]
@@ -126,8 +126,8 @@ public void ItCanConvertToFunctionDefinitionsWithParameterTypesAndNoReturnParame
{ "type": "object",
"required": ["param1", "param2"],
"properties": {
- "param1": { "type": "string", "description": "String param 1" },
- "param2": { "type": "integer", "description": "Int param 2" } } }
+ "param1": { "description": "String param 1", "type": "string" },
+ "param2": { "description": "Int param 2", "type": "integer"} } }
""";
KernelPlugin plugin = KernelPluginFactory.CreateFromFunctions("Tests", new[]
@@ -180,7 +180,7 @@ public void ItCanConvertToFunctionDefinitionsWithNoParameterTypesButWithDescript
// Assert
Assert.Equal(
- """{"type":"object","required":[],"properties":{"param1":{"type":"string","description":"something neat"}}}""",
+ """{"type":"object","required":[],"properties":{"param1":{"description":"something neat","type":"string"}}}""",
JsonSerializer.Serialize(result.Parameters));
}
}
diff --git a/dotnet/src/Connectors/Connectors.Google.UnitTests/Extensions/KernelFunctionMetadataExtensionsTests.cs b/dotnet/src/Connectors/Connectors.Google.UnitTests/Extensions/KernelFunctionMetadataExtensionsTests.cs
index 75552dc1f23b..99afbb5ec092 100644
--- a/dotnet/src/Connectors/Connectors.Google.UnitTests/Extensions/KernelFunctionMetadataExtensionsTests.cs
+++ b/dotnet/src/Connectors/Connectors.Google.UnitTests/Extensions/KernelFunctionMetadataExtensionsTests.cs
@@ -200,7 +200,7 @@ public void ItCanCreateValidGeminiFunctionManualForPlugin()
// Assert
Assert.NotNull(result);
Assert.Equal(
- """{"type":"object","required":["parameter1","parameter2","parameter3"],"properties":{"parameter1":{"type":"string","description":"String parameter"},"parameter2":{"type":"string","enum":["Value1","Value2"],"description":"Enum parameter"},"parameter3":{"type":"string","format":"date-time","description":"DateTime parameter"}}}""",
+ """{"type":"object","required":["parameter1","parameter2","parameter3"],"properties":{"parameter1":{"description":"String parameter","type":"string"},"parameter2":{"description":"Enum parameter","type":"string","enum":["Value1","Value2"]},"parameter3":{"description":"DateTime parameter","type":"string"}}}""",
JsonSerializer.Serialize(result.Parameters)
);
}
diff --git a/dotnet/src/Connectors/Connectors.OpenAI.UnitTests/Core/OpenAIFunctionTests.cs b/dotnet/src/Connectors/Connectors.OpenAI.UnitTests/Core/OpenAIFunctionTests.cs
index 1967ee882ec8..ffafba5a446d 100644
--- a/dotnet/src/Connectors/Connectors.OpenAI.UnitTests/Core/OpenAIFunctionTests.cs
+++ b/dotnet/src/Connectors/Connectors.OpenAI.UnitTests/Core/OpenAIFunctionTests.cs
@@ -92,7 +92,7 @@ public void ItCanConvertToFunctionDefinitionWithPluginName()
[Fact]
public void ItCanConvertToFunctionDefinitionsWithParameterTypesAndReturnParameterType()
{
- string expectedParameterSchema = """{ "type": "object", "required": ["param1", "param2"], "properties": { "param1": { "type": "string", "description": "String param 1" }, "param2": { "type": "integer", "description": "Int param 2" } } } """;
+ string expectedParameterSchema = """{ "type": "object", "required": ["param1", "param2"], "properties": { "param1": { "description": "String param 1", "type": "string" }, "param2": { "description": "Int param 2", "type": "integer" } } } """;
KernelPlugin plugin = KernelPluginFactory.CreateFromFunctions("Tests", new[]
{
@@ -118,7 +118,7 @@ public void ItCanConvertToFunctionDefinitionsWithParameterTypesAndReturnParamete
[Fact]
public void ItCanConvertToFunctionDefinitionsWithParameterTypesAndNoReturnParameterType()
{
- string expectedParameterSchema = """{ "type": "object", "required": ["param1", "param2"], "properties": { "param1": { "type": "string", "description": "String param 1" }, "param2": { "type": "integer", "description": "Int param 2" } } } """;
+ string expectedParameterSchema = """{ "type": "object", "required": ["param1", "param2"], "properties": { "param1": { "description": "String param 1", "type": "string" }, "param2": { "description": "Int param 2", "type": "integer" } } } """;
KernelPlugin plugin = KernelPluginFactory.CreateFromFunctions("Tests", new[]
{
@@ -174,7 +174,7 @@ public void ItCanConvertToFunctionDefinitionsWithNoParameterTypesButWithDescript
Assert.NotNull(pd.properties);
Assert.Single(pd.properties);
Assert.Equal(
- JsonSerializer.Serialize(KernelJsonSchema.Parse("""{ "type":"string", "description":"something neat" }""")),
+ JsonSerializer.Serialize(KernelJsonSchema.Parse("""{ "description":"something neat", "type":"string" }""")),
JsonSerializer.Serialize(pd.properties.First().Value.RootElement));
}
diff --git a/dotnet/src/Connectors/Connectors.OpenAI.UnitTests/Core/OpenAIJsonSchemaTransformerTests.cs b/dotnet/src/Connectors/Connectors.OpenAI.UnitTests/Core/OpenAIJsonSchemaTransformerTests.cs
index 29ed2ba3f5e6..d1690f560473 100644
--- a/dotnet/src/Connectors/Connectors.OpenAI.UnitTests/Core/OpenAIJsonSchemaTransformerTests.cs
+++ b/dotnet/src/Connectors/Connectors.OpenAI.UnitTests/Core/OpenAIJsonSchemaTransformerTests.cs
@@ -3,24 +3,23 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Text.Json;
-using JsonSchemaMapper;
+using Microsoft.Extensions.AI;
using Microsoft.SemanticKernel;
-using Microsoft.SemanticKernel.Connectors.OpenAI;
using Xunit;
namespace SemanticKernel.Connectors.OpenAI.UnitTests.Core;
///
-/// Unit tests for class.
+/// Unit tests for schema transformations used by OpenAI clients.
///
public sealed class OpenAIJsonSchemaTransformerTests
{
- private static readonly JsonSchemaMapperConfiguration s_jsonSchemaMapperConfiguration = new()
+ private static readonly AIJsonSchemaCreateOptions s_jsonSchemaCreateOptions = new()
{
- IncludeSchemaVersion = false,
- IncludeTypeInEnums = true,
- TreatNullObliviousAsNonNullable = true,
- TransformSchemaNode = OpenAIJsonSchemaTransformer.Transform,
+ IncludeSchemaKeyword = false,
+ IncludeTypeInEnumSchemas = true,
+ DisallowAdditionalProperties = true,
+ RequireAllProperties = true,
};
private static readonly JsonSerializerOptions s_jsonSerializerOptions = new()
@@ -124,7 +123,7 @@ public void ItTransformsJsonSchemaCorrectly()
""";
// Act
- var schema = KernelJsonSchemaBuilder.Build(type, configuration: s_jsonSchemaMapperConfiguration);
+ var schema = KernelJsonSchemaBuilder.Build(type, configuration: s_jsonSchemaCreateOptions);
// Assert
Assert.Equal(NormalizeJson(expectedSchema), NormalizeJson(schema.ToString()));
diff --git a/dotnet/src/Connectors/Connectors.OpenAI.UnitTests/Extensions/KernelFunctionMetadataExtensionsTests.cs b/dotnet/src/Connectors/Connectors.OpenAI.UnitTests/Extensions/KernelFunctionMetadataExtensionsTests.cs
index e817d559aeaa..ce518ded70f9 100644
--- a/dotnet/src/Connectors/Connectors.OpenAI.UnitTests/Extensions/KernelFunctionMetadataExtensionsTests.cs
+++ b/dotnet/src/Connectors/Connectors.OpenAI.UnitTests/Extensions/KernelFunctionMetadataExtensionsTests.cs
@@ -196,7 +196,7 @@ public void ItCanCreateValidAzureOpenAIFunctionManualForPlugin()
// Assert
Assert.NotNull(result);
Assert.Equal(
- """{"type":"object","required":["parameter1","parameter2","parameter3"],"properties":{"parameter1":{"type":"string","description":"String parameter"},"parameter2":{"type":"string","enum":["Value1","Value2"],"description":"Enum parameter"},"parameter3":{"type":"string","format":"date-time","description":"DateTime parameter"}}}""",
+ """{"type":"object","required":["parameter1","parameter2","parameter3"],"properties":{"parameter1":{"description":"String parameter","type":"string"},"parameter2":{"description":"Enum parameter","type":"string","enum":["Value1","Value2"]},"parameter3":{"description":"DateTime parameter","type":"string"}}}""",
result.FunctionParameters.ToString()
);
}
diff --git a/dotnet/src/Connectors/Connectors.OpenAI/Core/OpenAIJsonSchemaTransformer.cs b/dotnet/src/Connectors/Connectors.OpenAI/Core/OpenAIJsonSchemaTransformer.cs
deleted file mode 100644
index 73a0fbfb711d..000000000000
--- a/dotnet/src/Connectors/Connectors.OpenAI/Core/OpenAIJsonSchemaTransformer.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-using System.Collections.Generic;
-using System.Linq;
-using System.Text.Json.Nodes;
-using JsonSchemaMapper;
-
-namespace Microsoft.SemanticKernel.Connectors.OpenAI;
-
-///
-/// JSON Schema transformer to apply OpenAI conditions for structured outputs.
-///
-/// - "additionalProperties" property must always be set to in objects.
-/// More information here: .
-///
-///
-/// - All fields must be "required".
-/// More information here: .
-///
-///
-internal static class OpenAIJsonSchemaTransformer
-{
- private const string AdditionalPropertiesPropertyName = "additionalProperties";
- private const string TypePropertyName = "type";
- private const string ObjectValueName = "object";
- private const string PropertiesPropertyName = "properties";
- private const string RequiredPropertyName = "required";
-
- internal static JsonNode Transform(JsonSchemaGenerationContext context, JsonNode schema)
- {
- // Transform schema if node is object only.
- if (schema is JsonObject jsonSchemaObject)
- {
- var types = GetTypes(jsonSchemaObject);
-
- if (types is not null && types.Contains(ObjectValueName))
- {
- // Set "additionalProperties" to "false".
- jsonSchemaObject[AdditionalPropertiesPropertyName] = false;
-
- // Specify all properties as "required".
- if (jsonSchemaObject.TryGetPropertyValue(PropertiesPropertyName, out var properties) &&
- properties is JsonObject propertiesObject)
- {
- var propertyNames = propertiesObject.Select(l => (JsonNode)l.Key).ToArray();
-
- jsonSchemaObject[RequiredPropertyName] = new JsonArray(propertyNames);
- }
- }
- }
-
- return schema;
- }
-
- private static List? GetTypes(JsonObject jsonObject)
- {
- if (jsonObject.TryGetPropertyValue(TypePropertyName, out var typeProperty) && typeProperty is not null)
- {
- // For cases when "type" has an array value (e.g "type": "["object", "null"]").
- if (typeProperty is JsonArray nodeArray)
- {
- return nodeArray.ToArray().Select(element => element?.GetValue()).ToList();
- }
-
- // Case when "type" has a string value (e.g. "type": "object").
- return [typeProperty.GetValue()];
- }
-
- return null;
- }
-}
diff --git a/dotnet/src/Connectors/Connectors.OpenAI/Helpers/OpenAIChatResponseFormatBuilder.cs b/dotnet/src/Connectors/Connectors.OpenAI/Helpers/OpenAIChatResponseFormatBuilder.cs
index 835d4c19ae32..e032335dbe5a 100644
--- a/dotnet/src/Connectors/Connectors.OpenAI/Helpers/OpenAIChatResponseFormatBuilder.cs
+++ b/dotnet/src/Connectors/Connectors.OpenAI/Helpers/OpenAIChatResponseFormatBuilder.cs
@@ -3,7 +3,6 @@
using System;
using System.Text;
using System.Text.Json;
-using JsonSchemaMapper;
using OpenAI.Chat;
namespace Microsoft.SemanticKernel.Connectors.OpenAI;
@@ -14,14 +13,14 @@ namespace Microsoft.SemanticKernel.Connectors.OpenAI;
internal static class OpenAIChatResponseFormatBuilder
{
///
- /// for JSON schema format for structured outputs.
+ /// for JSON schema format for structured outputs.
///
- private static readonly JsonSchemaMapperConfiguration s_jsonSchemaMapperConfiguration = new()
+ private static readonly Microsoft.Extensions.AI.AIJsonSchemaCreateOptions s_jsonSchemaCreateOptions = new()
{
- IncludeSchemaVersion = false,
- IncludeTypeInEnums = true,
- TreatNullObliviousAsNonNullable = true,
- TransformSchemaNode = OpenAIJsonSchemaTransformer.Transform
+ IncludeSchemaKeyword = false,
+ IncludeTypeInEnumSchemas = true,
+ DisallowAdditionalProperties = true,
+ RequireAllProperties = true,
};
///
@@ -56,7 +55,7 @@ internal static ChatResponseFormat GetJsonSchemaResponseFormat(Type formatObject
{
var type = formatObjectType.IsGenericType && formatObjectType.GetGenericTypeDefinition() == typeof(Nullable<>) ? Nullable.GetUnderlyingType(formatObjectType)! : formatObjectType;
- var schema = KernelJsonSchemaBuilder.Build(type, configuration: s_jsonSchemaMapperConfiguration);
+ var schema = KernelJsonSchemaBuilder.Build(type, configuration: s_jsonSchemaCreateOptions);
var schemaBinaryData = BinaryData.FromString(schema.ToString());
var typeName = GetTypeName(type);
diff --git a/dotnet/src/InternalUtilities/src/Schema/.editorconfig b/dotnet/src/InternalUtilities/src/Schema/.editorconfig
deleted file mode 100644
index 76e8ee827086..000000000000
--- a/dotnet/src/InternalUtilities/src/Schema/.editorconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-# Suppressing code analysis diagnostics for code included as a source copy
-[*.cs]
-dotnet_diagnostic.CA1852.severity = none
-dotnet_diagnostic.IDE0005.severity = none
-dotnet_diagnostic.IDE0009.severity = none
-dotnet_diagnostic.IDE0055.severity = none
-dotnet_diagnostic.IDE0161.severity = none
-dotnet_diagnostic.IDE1006.severity = none
-dotnet_diagnostic.RCS1211.severity = none
\ No newline at end of file
diff --git a/dotnet/src/InternalUtilities/src/Schema/JsonSchemaGenerationContext.cs b/dotnet/src/InternalUtilities/src/Schema/JsonSchemaGenerationContext.cs
deleted file mode 100644
index 05955507277a..000000000000
--- a/dotnet/src/InternalUtilities/src/Schema/JsonSchemaGenerationContext.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-
-// Source copied from https://github.com/eiriktsarpalis/stj-schema-mapper
-// It should be kept in sync with any changes made in that repo,
-// and should be removed once the relevant replacements are available in STJv9.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reflection;
-using System.Text.Json.Serialization.Metadata;
-
-namespace JsonSchemaMapper;
-
-///
-/// Defines the context in which a JSON schema within a type graph is being generated.
-///
-#if EXPOSE_JSON_SCHEMA_MAPPER
-public
-#else
-internal
-#endif
- readonly struct JsonSchemaGenerationContext
-{
- internal JsonSchemaGenerationContext(
- JsonTypeInfo typeInfo,
- Type? declaringType,
- JsonPropertyInfo? propertyInfo,
- ParameterInfo? parameterInfo,
- ICustomAttributeProvider? propertyAttributeProvider)
- {
- TypeInfo = typeInfo;
- DeclaringType = declaringType;
- PropertyInfo = propertyInfo;
- ParameterInfo = parameterInfo;
- PropertyAttributeProvider = propertyAttributeProvider;
- }
-
- ///
- /// The for the type being processed.
- ///
- public JsonTypeInfo TypeInfo { get; }
-
- ///
- /// The declaring type of the property or parameter being processed.
- ///
- public Type? DeclaringType { get; }
-
- ///
- /// The if the schema is being generated for a property.
- ///
- public JsonPropertyInfo? PropertyInfo { get; }
-
- ///
- /// The if a constructor parameter
- /// has been associated with the accompanying .
- ///
- public ParameterInfo? ParameterInfo { get; }
-
- ///
- /// The corresponding to the property or field being processed.
- ///
- public ICustomAttributeProvider? PropertyAttributeProvider { get; }
-
- ///
- /// Checks if the type, property, or parameter has the specified attribute applied.
- ///
- /// The type of the attribute to resolve.
- /// Whether to look up the hierarchy chain for the inherited custom attribute.
- /// True if the attribute is defined by the current context.
- public bool IsDefined(bool inherit = false)
- where TAttribute : Attribute =>
- GetCustomAttributes(typeof(TAttribute), inherit).Any();
-
- ///
- /// Checks if the type, property, or parameter has the specified attribute applied.
- ///
- /// The type of the attribute to resolve.
- /// Whether to look up the hierarchy chain for the inherited custom attribute.
- /// The first attribute resolved from the current context, or null.
- public TAttribute? GetAttribute(bool inherit = false)
- where TAttribute : Attribute =>
- (TAttribute?)GetCustomAttributes(typeof(TAttribute), inherit).FirstOrDefault();
-
- ///
- /// Resolves any custom attributes that might have been applied to the type, property, or parameter.
- ///
- /// The attribute type to resolve.
- /// Whether to look up the hierarchy chain for the inherited custom attribute.
- /// An enumerable of all custom attributes defined by the context.
- public IEnumerable GetCustomAttributes(Type type, bool inherit = false)
- {
- // Resolves attributes starting from the property, then the parameter, and finally the type itself.
- return GetAttrs(PropertyAttributeProvider)
- .Concat(GetAttrs(ParameterInfo))
- .Concat(GetAttrs(TypeInfo.Type))
- .Cast();
-
- object[] GetAttrs(ICustomAttributeProvider? provider) =>
- provider?.GetCustomAttributes(type, inherit) ?? Array.Empty