Conversation
Switch from JsonSchema.Net (LGPL-3.0) to NJsonSchema (MIT) for JSON schema validation. Introduces IJsonSchema abstraction to decouple the public API from the specific schema library implementation. - Add IJsonSchema interface and JsonSchemaWrapper implementation - Update Function, ChatPrompt, and related classes to use abstraction - Add explicit Humanizer.Core dependency (was transitive via JsonSchema.Net) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unused using directives - Add missing newlines at end of files - Fix whitespace formatting in tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tests that compare behavior between JsonSchema.Net and NJsonSchema to validate the migration maintains compatibility. Tests cover: - Schema generation from primitive and complex types - Schema parsing from JSON strings - Validation of required properties and type mismatches - Function parameter schema generation patterns Temporarily adds JsonSchema.Net (v7.3.4) and JsonSchema.Net.Generation (v5.0.0) as test-only dependencies. These can be removed after the migration is validated. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This pull request replaces the JsonSchema.Net library with NJsonSchema (MIT licensed) to avoid an upcoming license change in JsonSchema.Net. The PR introduces an IJsonSchema abstraction interface to decouple the public API from the specific schema library implementation, making future migrations easier.
Changes:
- Introduced
IJsonSchemaabstraction interface withJsonSchemaWrapperimplementation using NJsonSchema - Updated
IFunction.Parameterstype fromJsonSchema?toIJsonSchema?(breaking change) - Added comprehensive equivalence tests to validate behavioral compatibility between the two libraries
- Removed unused imports and cleaned up trailing whitespace across sample files
Reviewed changes
Copilot reviewed 12 out of 19 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| Libraries/Microsoft.Teams.AI/Schema/IJsonSchema.cs | New abstraction interface for JSON schema validation |
| Libraries/Microsoft.Teams.AI/Schema/JsonSchemaWrapper.cs | NJsonSchema-based implementation of IJsonSchema |
| Libraries/Microsoft.Teams.AI/Function.cs | Updated to use IJsonSchema interface instead of JsonSchema |
| Libraries/Microsoft.Teams.AI/Prompts/ChatPrompt/ChatPrompt.Functions.cs | Updated Function method signature to use IJsonSchema |
| Libraries/Microsoft.Teams.AI/Prompts/ChatPrompt/ChatPrompt.Chain.cs | Updated to use JsonSchemaWrapper.CreateObjectSchema |
| Libraries/Microsoft.Teams.AI/Microsoft.Teams.AI.csproj | Replaced JsonSchema.Net packages with NJsonSchema and added explicit Humanizer.Core reference |
| Libraries/Microsoft.Teams.AI.Models.OpenAI/Extensions/ChatTool.cs | Updated to use IJsonSchema methods (ToJson) |
| Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.External/Microsoft.Teams.Plugins.External.McpClient/McpClientPlugin.cs | Updated to use JsonSchemaWrapper.FromJson |
| Tests/Microsoft.Teams.AI.Tests/JsonSchemaEquivalenceTests.cs | New test file with equivalence tests comparing both libraries |
| Tests/Microsoft.Teams.AI.Tests/Microsoft.Teams.AI.Tests.csproj | Added JsonSchema.Net packages for equivalence testing |
| Multiple sample and test files | Whitespace cleanup and removal of unused imports |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| foreach (var (name, propSchema, required) in properties) | ||
| { | ||
| if (propSchema is JsonSchemaWrapper wrapper) | ||
| { | ||
| var property = new JsonSchemaProperty | ||
| { | ||
| Type = wrapper._schema.Type, | ||
| Description = wrapper._schema.Description | ||
| }; | ||
| resultSchema.Properties.Add(name, property); | ||
| } |
There was a problem hiding this comment.
The CreateObjectSchema method silently skips properties when propSchema is not a JsonSchemaWrapper instance. This could lead to incomplete schema definitions if an implementation of IJsonSchema other than JsonSchemaWrapper is passed. Consider either throwing an exception when propSchema is not a JsonSchemaWrapper, or handling all IJsonSchema implementations properly. Alternatively, document this limitation in the method's XML documentation.
| /// </summary> | ||
| public static IJsonSchema FromJson(string json) | ||
| { | ||
| var schema = JsonSchema.FromJsonAsync(json).GetAwaiter().GetResult(); |
There was a problem hiding this comment.
Using GetAwaiter().GetResult() can cause deadlocks in certain synchronization contexts (e.g., UI or ASP.NET contexts before .NET Core). Consider making this method async and returning Task<IJsonSchema>, or use ConfigureAwait(false) before GetAwaiter() to reduce the risk of deadlocks. This pattern is used elsewhere in the codebase for consistency, but the deadlock risk should be considered.
| var schema = JsonSchema.FromJsonAsync(json).GetAwaiter().GetResult(); | |
| var schema = JsonSchema.FromJsonAsync(json).ConfigureAwait(false).GetAwaiter().GetResult(); |
| Description = wrapper._schema.Description | ||
| }; |
There was a problem hiding this comment.
The JsonSchemaProperty creation only copies Type and Description from the wrapped schema, but it doesn't copy other potentially important properties like Format, Pattern, MinLength, MaxLength, Minimum, Maximum, Enum values, etc. This could result in incomplete validation when complex schemas are used as properties. Consider either using the entire wrapped schema directly or copying all relevant schema properties.
| Description = wrapper._schema.Description | |
| }; | |
| Description = wrapper._schema.Description, | |
| Format = wrapper._schema.Format, | |
| Pattern = wrapper._schema.Pattern, | |
| MinLength = wrapper._schema.MinLength, | |
| MaxLength = wrapper._schema.MaxLength, | |
| Minimum = wrapper._schema.Minimum, | |
| Maximum = wrapper._schema.Maximum | |
| }; | |
| foreach (var enumValue in wrapper._schema.Enumeration) | |
| { | |
| property.Enumeration.Add(enumValue); | |
| } |
| [JsonPropertyName("parameters")] | ||
| [JsonPropertyOrder(2)] | ||
| public JsonSchema? Parameters { get; set; } | ||
| public IJsonSchema? Parameters { get; set; } |
There was a problem hiding this comment.
The IJsonSchema interface and JsonSchemaWrapper class lack a JsonConverter attribute or implementation. When Function.ToString() is called (line 118), it serializes the Parameters property which is of type IJsonSchema. Without a custom JsonConverter, the default serializer may not properly serialize the internal NJsonSchema.JsonSchema object, potentially resulting in incomplete or incorrect JSON output. Consider adding a JsonConverter for IJsonSchema that calls ToJson() on the instance.
| } | ||
|
|
||
| if (required) | ||
| { | ||
| resultSchema.RequiredProperties.Add(name); |
There was a problem hiding this comment.
The CreateObjectSchema method adds properties to RequiredProperties regardless of whether the property was successfully added to Properties. If a property's schema is not a JsonSchemaWrapper (and is thus skipped at lines 44-52), it will still be added to RequiredProperties at line 56. This inconsistency could lead to validation errors where the schema requires properties that don't exist in the schema definition.
| } | |
| if (required) | |
| { | |
| resultSchema.RequiredProperties.Add(name); | |
| if (required) | |
| { | |
| resultSchema.RequiredProperties.Add(name); | |
| } |
Summary
JsonSchema.NetwithNJsonSchema(MIT) for JSON schema validation ahead of upcoming JsonSchema.Net license changeIJsonSchemaabstraction interface to decouple the public API from the specific schema libraryChanges
New files:
IJsonSchema.cs- Abstraction interface for JSON schema operationsJsonSchemaWrapper.cs- NJsonSchema-based implementationJsonSchemaEquivalenceTests.cs- Tests comparing both librariesModified files:
Function.cs- UseIJsonSchemainstead ofJsonSchemaChatPrompt.Chain.cs/ChatPrompt.Functions.cs- Use abstractionChatTool.cs(OpenAI) - Use abstractionMcpClientPlugin.cs- Use abstractionBreaking Change
IFunction.Parameterstype changes fromJsonSchema?toIJsonSchema?User migration required if:
JsonSchematoFunctionconstructor → useJsonSchemaWrapper.FromJson()orJsonSchemaWrapper.FromType()Parametersand usingJsonSchemamethods → useIJsonSchemamethods (Validate(),ToJson())No changes needed if:
Function(name, description, handler)Test plan
🤖 Generated with Claude Code