diff --git a/app/MindWork AI Studio/Tools/ERIClient/ERIClientBase.cs b/app/MindWork AI Studio/Tools/ERIClient/ERIClientBase.cs index 7d8f0cbe8..9b616d85f 100644 --- a/app/MindWork AI Studio/Tools/ERIClient/ERIClientBase.cs +++ b/app/MindWork AI Studio/Tools/ERIClient/ERIClientBase.cs @@ -9,7 +9,7 @@ public abstract class ERIClientBase(IERIDataSource dataSource) : IDisposable { protected readonly IERIDataSource DataSource = dataSource; - internal static readonly JsonSerializerOptions JSON_OPTIONS = new() + internal static readonly JsonSerializerOptions JSON_OPTIONS = new JsonSerializerOptions { WriteIndented = true, AllowTrailingCommas = true, @@ -20,8 +20,9 @@ public abstract class ERIClientBase(IERIDataSource dataSource) : IDisposable Converters = { new JsonStringEnumConverter(JsonNamingPolicy.SnakeCaseUpper), - } - }; + }, + TypeInfoResolver = ERIClientJsonContext.Default, + }.AsReadOnly(); protected readonly HttpClient HttpClient = ExternalHttpClientTimeout.CreateHttpClient(new Uri($"{dataSource.Hostname}:{dataSource.Port}"), ExternalHttpTrustPolicy.ALLOW_CUSTOM_ROOTS_WHEN_HOST_WHITELISTED); diff --git a/app/MindWork AI Studio/Tools/ERIClient/ERIClientJsonContext.cs b/app/MindWork AI Studio/Tools/ERIClient/ERIClientJsonContext.cs new file mode 100644 index 000000000..30db29e2b --- /dev/null +++ b/app/MindWork AI Studio/Tools/ERIClient/ERIClientJsonContext.cs @@ -0,0 +1,23 @@ +using System.Text.Json.Serialization; + +using AIStudio.Tools.ERIClient.DataModel; + +namespace AIStudio.Tools.ERIClient; + +/// +/// The contracts with which System.Text.Json reads and writes the calls to ERI servers, built at compile time. +/// +[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)] + +// The request: +[JsonSerializable(typeof(RetrievalRequest))] + +// The answers: +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(AuthResponse))] +[JsonSerializable(typeof(DataSourceInfo))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(List))] +[JsonSerializable(typeof(SecurityRequirements))] +internal sealed partial class ERIClientJsonContext : JsonSerializerContext; \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchJson.cs b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchJson.cs index 6ac1d24aa..136c31e8a 100644 --- a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchJson.cs +++ b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchJson.cs @@ -14,10 +14,11 @@ namespace AIStudio.Tools.ToolCallingSystem.ToolCallingImplementations.WebSearch; /// internal static class WebSearchJson { - public static readonly JsonSerializerOptions OPTIONS = new() + public static readonly JsonSerializerOptions OPTIONS = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, PropertyNameCaseInsensitive = true, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, - }; + TypeInfoResolver = WebSearchJsonContext.Default, + }.AsReadOnly(); } \ No newline at end of file diff --git a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchJsonContext.cs b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchJsonContext.cs new file mode 100644 index 000000000..8185029af --- /dev/null +++ b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolCallingImplementations/WebSearch/WebSearchJsonContext.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; + +using AIStudio.Tools.ToolCallingSystem.ToolCallingImplementations.WebSearch.Staan; +using AIStudio.Tools.ToolCallingSystem.ToolCallingImplementations.WebSearch.Tavily; + +namespace AIStudio.Tools.ToolCallingSystem.ToolCallingImplementations.WebSearch; + +/// +/// The contracts with which System.Text.Json reads and writes the calls to the search services, built at +/// compile time. +/// +/// +/// SearXNG is missing on purpose: its answers differ between instances, so its client reads them as a tree +/// of JSON nodes instead. +/// +[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)] +[JsonSerializable(typeof(StaanSearchRequest))] +[JsonSerializable(typeof(StaanSearchResponse))] +[JsonSerializable(typeof(TavilySearchRequest))] +[JsonSerializable(typeof(TavilySearchResponse))] +internal sealed partial class WebSearchJsonContext : JsonSerializerContext; \ No newline at end of file diff --git a/app/Tests/Serialization/JsonCoverageTests.cs b/app/Tests/Serialization/JsonCoverageTests.cs index e40776b90..716585793 100644 --- a/app/Tests/Serialization/JsonCoverageTests.cs +++ b/app/Tests/Serialization/JsonCoverageTests.cs @@ -18,6 +18,8 @@ public sealed class JsonCoverageTests [TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ProviderAnswers))] [TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.RuntimeRequests))] [TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.RuntimeAnswers))] + [TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ServiceRequests))] + [TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ServiceAnswers))] public void EveryContractComesFromSourceGeneration(JsonTestRoot root) { var typesWithoutGeneratedContract = JsonTypeGraph.Collect(root.Type, root.Options)