From 05091b635c481be355e2d954932f89a5ea4cd290 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Mon, 29 Dec 2025 18:12:11 +0100 Subject: [PATCH] Add custom JSON converters for ISubContent and ISubContentImageSource to support polymorphic serialization --- .../SubContentImageSourceConverter.cs | 32 +++++++++++++++++ .../Provider/BaseProvider.cs | 11 +++++- .../Provider/SubContentConverter.cs | 34 +++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 app/MindWork AI Studio/Provider/Anthropic/SubContentImageSourceConverter.cs create mode 100644 app/MindWork AI Studio/Provider/SubContentConverter.cs diff --git a/app/MindWork AI Studio/Provider/Anthropic/SubContentImageSourceConverter.cs b/app/MindWork AI Studio/Provider/Anthropic/SubContentImageSourceConverter.cs new file mode 100644 index 00000000..11c61ad2 --- /dev/null +++ b/app/MindWork AI Studio/Provider/Anthropic/SubContentImageSourceConverter.cs @@ -0,0 +1,32 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace AIStudio.Provider.Anthropic; + +/// +/// Custom JSON converter for the ISubContentImageSource interface to handle polymorphic serialization. +/// +/// +/// This converter ensures that when serializing ISubContentImageSource objects, all properties +/// of the concrete implementation (e.g., SubContentBase64Image, SubContentImageUrl) are serialized, +/// not just the properties defined in the ISubContentImageSource interface. +/// +public sealed class SubContentImageSourceConverter : JsonConverter +{ + private static readonly ILogger LOGGER = Program.LOGGER_FACTORY.CreateLogger(); + + public override ISubContentImageSource? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + // Deserialization is not needed for request objects, as sub-content image sources are only serialized + // when sending requests to LLM providers. + LOGGER.LogError("Deserializing ISubContentImageSource is not supported. This converter is only used for serializing request messages."); + return null; + } + + public override void Write(Utf8JsonWriter writer, ISubContentImageSource value, JsonSerializerOptions options) + { + // Serialize the actual concrete type (e.g., SubContentBase64Image, SubContentImageUrl) instead of just the ISubContentImageSource interface. + // This ensures all properties of the concrete type are included in the JSON output. + JsonSerializer.Serialize(writer, value, value.GetType(), options); + } +} diff --git a/app/MindWork AI Studio/Provider/BaseProvider.cs b/app/MindWork AI Studio/Provider/BaseProvider.cs index 0490b6f0..48e7716e 100644 --- a/app/MindWork AI Studio/Provider/BaseProvider.cs +++ b/app/MindWork AI Studio/Provider/BaseProvider.cs @@ -1,8 +1,10 @@ using System.Net; using System.Runtime.CompilerServices; using System.Text.Json; +using System.Text.Json.Serialization; using AIStudio.Chat; +using AIStudio.Provider.Anthropic; using AIStudio.Provider.OpenAI; using AIStudio.Settings; using AIStudio.Tools.PluginSystem; @@ -40,7 +42,14 @@ public abstract class BaseProvider : IProvider, ISecretId protected static readonly JsonSerializerOptions JSON_SERIALIZER_OPTIONS = new() { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower, - Converters = { new AnnotationConverter(), new MessageBaseConverter() }, + Converters = + { + new JsonStringEnumConverter(JsonNamingPolicy.SnakeCaseLower), + new AnnotationConverter(), + new MessageBaseConverter(), + new SubContentConverter(), + new SubContentImageSourceConverter(), + }, AllowTrailingCommas = false }; diff --git a/app/MindWork AI Studio/Provider/SubContentConverter.cs b/app/MindWork AI Studio/Provider/SubContentConverter.cs new file mode 100644 index 00000000..cd257a3d --- /dev/null +++ b/app/MindWork AI Studio/Provider/SubContentConverter.cs @@ -0,0 +1,34 @@ +using System.Text.Json; +using System.Text.Json.Serialization; + +using AIStudio.Provider.OpenAI; + +namespace AIStudio.Provider; + +/// +/// Custom JSON converter for the ISubContent interface to handle polymorphic serialization. +/// +/// +/// This converter ensures that when serializing ISubContent objects, all properties +/// of the concrete implementation (e.g., SubContentText, SubContentImageUrl) are serialized, +/// not just the properties defined in the ISubContent interface. +/// +public sealed class SubContentConverter : JsonConverter +{ + private static readonly ILogger LOGGER = Program.LOGGER_FACTORY.CreateLogger(); + + public override ISubContent? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + // Deserialization is not needed for request objects, as sub-content is only serialized + // when sending requests to LLM providers. + LOGGER.LogError("Deserializing ISubContent is not supported. This converter is only used for serializing request messages."); + return null; + } + + public override void Write(Utf8JsonWriter writer, ISubContent value, JsonSerializerOptions options) + { + // Serialize the actual concrete type (e.g., SubContentText, SubContentImageUrl) instead of just the ISubContent interface. + // This ensures all properties of the concrete type are included in the JSON output. + JsonSerializer.Serialize(writer, value, value.GetType(), options); + } +}