From 9397b131487b80544da568c226c0941badc275ce Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Tue, 3 Nov 2026 14:54:43 +0100 Subject: [PATCH] Stopped the tool results and the JSON tree view from building JSON contracts by reflection --- .../Components/JsonTreeView.razor.cs | 3 +-- .../ToolCallingSystem/ToolExecutionResult.cs | 6 +++++- .../ToolExecutionResultJsonContext.cs | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 app/MindWork AI Studio/Tools/ToolCallingSystem/ToolExecutionResultJsonContext.cs diff --git a/app/MindWork AI Studio/Components/JsonTreeView.razor.cs b/app/MindWork AI Studio/Components/JsonTreeView.razor.cs index a7e79070b..efc3d000a 100644 --- a/app/MindWork AI Studio/Components/JsonTreeView.razor.cs +++ b/app/MindWork AI Studio/Components/JsonTreeView.razor.cs @@ -1,4 +1,3 @@ -using System.Text.Json; using System.Text.Json.Nodes; using Microsoft.AspNetCore.Components; @@ -37,7 +36,7 @@ public partial class JsonTreeView : ComponentBase private static List> CreateChildren(JsonNode? value) => value switch { JsonObject jsonObject => jsonObject - .Select(property => CreateTreeItem(JsonSerializer.Serialize(property.Key), property.Value)) + .Select(property => CreateTreeItem(JsonValue.Create(property.Key).ToJsonString(), property.Value)) .ToList(), JsonArray jsonArray => jsonArray .Select((item, index) => CreateTreeItem($"[{index}]", item)) diff --git a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolExecutionResult.cs b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolExecutionResult.cs index 4708e8aef..243cf5cbc 100644 --- a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolExecutionResult.cs +++ b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolExecutionResult.cs @@ -21,7 +21,11 @@ public sealed class ToolExecutionResult /// with every umlaut as six characters. The relaxed encoder escapes only what JSON requires. /// // Internal, so a tool which keeps its result within a budget measures exactly what the model gets: - internal static readonly JsonSerializerOptions MODEL_CONTENT_OPTIONS = new() { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; + internal static readonly JsonSerializerOptions MODEL_CONTENT_OPTIONS = new JsonSerializerOptions + { + Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + TypeInfoResolver = ToolExecutionResultJsonContext.Default, + }.AsReadOnly(); public string? TextContent { get; init; } diff --git a/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolExecutionResultJsonContext.cs b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolExecutionResultJsonContext.cs new file mode 100644 index 000000000..65915c63d --- /dev/null +++ b/app/MindWork AI Studio/Tools/ToolCallingSystem/ToolExecutionResultJsonContext.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; + +namespace AIStudio.Tools.ToolCallingSystem; + +/// +/// The contracts of the options with which a tool result is written for the model, built at compile time. +/// +/// +/// A JSON result is a tree of JSON nodes, which writes itself and needs no contract from the options. The +/// context is there all the same, so that these options can never fall back to reflection either. +/// +[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)] +[JsonSerializable(typeof(JsonNode))] +internal sealed partial class ToolExecutionResultJsonContext : JsonSerializerContext; \ No newline at end of file