mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-04 02:48:56 +00:00
Generated the JSON contracts of the model answers and the Assistant Builder at compile time
This commit is contained in:
21 files changed
+150
-18
No files matched your search
@@ -19,10 +19,11 @@ public abstract class AgentBase(ILogger<AgentBase> logger, SettingsManager setti
|
|||||||
Time = DateTimeOffset.UtcNow,
|
Time = DateTimeOffset.UtcNow,
|
||||||
};
|
};
|
||||||
|
|
||||||
internal static readonly JsonSerializerOptions JSON_SERIALIZER_OPTIONS = new()
|
internal static readonly JsonSerializerOptions JSON_SERIALIZER_OPTIONS = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||||
};
|
TypeInfoResolver = AgentJsonContext.Default,
|
||||||
|
}.AsReadOnly();
|
||||||
|
|
||||||
protected DataSourceService DataSourceService { get; init; } = dataSourceService;
|
protected DataSourceService DataSourceService { get; init; } = dataSourceService;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
using AIStudio.Agents.AssistantAudit;
|
||||||
|
|
||||||
|
namespace AIStudio.Agents;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The contracts with which System.Text.Json reads the answers of the agents, built at compile time.
|
||||||
|
/// </summary>
|
||||||
|
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
|
||||||
|
[JsonSerializable(typeof(List<SelectedDataSource>))]
|
||||||
|
[JsonSerializable(typeof(RetrievalContextValidationResult))]
|
||||||
|
[JsonSerializable(typeof(AssistantAuditResult))]
|
||||||
|
internal sealed partial class AgentJsonContext : JsonSerializerContext;
|
||||||
@@ -14,13 +14,14 @@ internal sealed class LauncherTextsResponse
|
|||||||
{
|
{
|
||||||
public const string SCHEMA_VERSION_VALUE = "assistant_builder_launcher_texts_v1";
|
public const string SCHEMA_VERSION_VALUE = "assistant_builder_launcher_texts_v1";
|
||||||
|
|
||||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
internal static readonly JsonSerializerOptions JSON_OPTIONS = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||||
AllowTrailingCommas = false,
|
AllowTrailingCommas = false,
|
||||||
ReadCommentHandling = JsonCommentHandling.Disallow,
|
ReadCommentHandling = JsonCommentHandling.Disallow,
|
||||||
MaxDepth = 8,
|
MaxDepth = 8,
|
||||||
};
|
TypeInfoResolver = LauncherTextsResponseJsonContext.Default,
|
||||||
|
}.AsReadOnly();
|
||||||
|
|
||||||
public string SchemaVersion { get; set; } = string.Empty;
|
public string SchemaVersion { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace AIStudio.Assistants.Builder;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The contracts with which System.Text.Json reads the answer of a model which names a direct chat launcher, built
|
||||||
|
/// at compile time.
|
||||||
|
/// </summary>
|
||||||
|
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
|
||||||
|
[JsonSerializable(typeof(LauncherTextsResponse))]
|
||||||
|
internal sealed partial class LauncherTextsResponseJsonContext : JsonSerializerContext;
|
||||||
@@ -4,13 +4,14 @@ namespace AIStudio.Assistants.Builder;
|
|||||||
|
|
||||||
internal sealed partial class LuaResponse
|
internal sealed partial class LuaResponse
|
||||||
{
|
{
|
||||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
internal static readonly JsonSerializerOptions JSON_OPTIONS = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||||
AllowTrailingCommas = false,
|
AllowTrailingCommas = false,
|
||||||
ReadCommentHandling = JsonCommentHandling.Disallow,
|
ReadCommentHandling = JsonCommentHandling.Disallow,
|
||||||
MaxDepth = 32,
|
MaxDepth = 32,
|
||||||
};
|
TypeInfoResolver = LuaResponseJsonContext.Default,
|
||||||
|
}.AsReadOnly();
|
||||||
|
|
||||||
public static bool TryParse(string modelResponse, out LuaResponse response, out LuaResponseParseError error, out string technicalDetails)
|
public static bool TryParse(string modelResponse, out LuaResponse response, out LuaResponseParseError error, out string technicalDetails)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace AIStudio.Assistants.Builder;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The contracts with which System.Text.Json reads the answer of a model which writes an assistant plugin, built at
|
||||||
|
/// compile time.
|
||||||
|
/// </summary>
|
||||||
|
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
|
||||||
|
[JsonSerializable(typeof(LuaResponse))]
|
||||||
|
internal sealed partial class LuaResponseJsonContext : JsonSerializerContext;
|
||||||
@@ -13,13 +13,14 @@ namespace AIStudio.Assistants.ERI;
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal sealed class ERIServerFileList
|
internal sealed class ERIServerFileList
|
||||||
{
|
{
|
||||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
internal static readonly JsonSerializerOptions JSON_OPTIONS = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||||
AllowTrailingCommas = false,
|
AllowTrailingCommas = false,
|
||||||
ReadCommentHandling = JsonCommentHandling.Disallow,
|
ReadCommentHandling = JsonCommentHandling.Disallow,
|
||||||
MaxDepth = 8,
|
MaxDepth = 8,
|
||||||
};
|
TypeInfoResolver = ERIServerFileListJsonContext.Default,
|
||||||
|
}.AsReadOnly();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The paths of the files, relative to the base directory.
|
/// The paths of the files, relative to the base directory.
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace AIStudio.Assistants.ERI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The contracts with which System.Text.Json reads the files a model plans for an ERI server, built at compile time.
|
||||||
|
/// </summary>
|
||||||
|
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
|
||||||
|
[JsonSerializable(typeof(ERIServerFileList))]
|
||||||
|
internal sealed partial class ERIServerFileListJsonContext : JsonSerializerContext;
|
||||||
@@ -17,10 +17,11 @@ namespace AIStudio.Assistants.PromptOptimizer;
|
|||||||
|
|
||||||
public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialogPromptOptimizer>
|
public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialogPromptOptimizer>
|
||||||
{
|
{
|
||||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
internal static readonly JsonSerializerOptions JSON_OPTIONS = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
PropertyNameCaseInsensitive = true,
|
PropertyNameCaseInsensitive = true,
|
||||||
};
|
TypeInfoResolver = PromptOptimizationJsonContext.Default,
|
||||||
|
}.AsReadOnly();
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
private IDialogService DialogService { get; init; } = null!;
|
private IDialogService DialogService { get; init; } = null!;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace AIStudio.Assistants.PromptOptimizer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The contracts with which System.Text.Json reads the answer of the prompt optimizer, built at compile time.
|
||||||
|
/// </summary>
|
||||||
|
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
|
||||||
|
[JsonSerializable(typeof(PromptOptimizationResult))]
|
||||||
|
internal sealed partial class PromptOptimizationJsonContext : JsonSerializerContext;
|
||||||
@@ -16,10 +16,11 @@ namespace AIStudio.Assistants.SWOTAnalysis;
|
|||||||
internal static class SwotAnalysisModeration
|
internal static class SwotAnalysisModeration
|
||||||
{
|
{
|
||||||
// Internal rather than private, so that a test can check the JSON the moderator gets:
|
// Internal rather than private, so that a test can check the JSON the moderator gets:
|
||||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
internal static readonly JsonSerializerOptions JSON_OPTIONS = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
WriteIndented = true,
|
WriteIndented = true,
|
||||||
};
|
TypeInfoResolver = SwotModerationJsonContext.Default,
|
||||||
|
}.AsReadOnly();
|
||||||
|
|
||||||
public static string BuildSystemPrompt(string outputLanguageInstruction) =>
|
public static string BuildSystemPrompt(string outputLanguageInstruction) =>
|
||||||
$"""
|
$"""
|
||||||
|
|||||||
@@ -8,13 +8,14 @@ namespace AIStudio.Assistants.SWOTAnalysis;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class SwotModelAnswer
|
internal static class SwotModelAnswer
|
||||||
{
|
{
|
||||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
internal static readonly JsonSerializerOptions JSON_OPTIONS = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
PropertyNameCaseInsensitive = true,
|
PropertyNameCaseInsensitive = true,
|
||||||
AllowTrailingCommas = true,
|
AllowTrailingCommas = true,
|
||||||
ReadCommentHandling = JsonCommentHandling.Skip,
|
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||||
RespectNullableAnnotations = true,
|
RespectNullableAnnotations = true,
|
||||||
};
|
TypeInfoResolver = SwotModelAnswerJsonContext.Default,
|
||||||
|
}.AsReadOnly();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads the JSON object of a model answer into the given type, without checking its content.
|
/// Reads the JSON object of a model answer into the given type, without checking its content.
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace AIStudio.Assistants.SWOTAnalysis;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The contracts with which System.Text.Json reads the answers of the models which work on a SWOT analysis, built at
|
||||||
|
/// compile time.
|
||||||
|
/// </summary>
|
||||||
|
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
|
||||||
|
[JsonSerializable(typeof(SwotCategoryAnalysisResult))]
|
||||||
|
[JsonSerializable(typeof(SwotModerationResult))]
|
||||||
|
internal sealed partial class SwotModelAnswerJsonContext : JsonSerializerContext;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace AIStudio.Assistants.SWOTAnalysis;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The contracts with which System.Text.Json writes the preliminary results the moderator of a SWOT analysis gets,
|
||||||
|
/// built at compile time.
|
||||||
|
/// </summary>
|
||||||
|
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
|
||||||
|
[JsonSerializable(typeof(Dictionary<string, SwotModerationCategoryInput>))]
|
||||||
|
internal sealed partial class SwotModerationJsonContext : JsonSerializerContext;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace AIStudio.Tools.PowerPoint;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The contracts with which System.Text.Json reads the slides a model plans, built at compile time.
|
||||||
|
/// </summary>
|
||||||
|
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
|
||||||
|
[JsonSerializable(typeof(SlideDeckSpec.DeckDto))]
|
||||||
|
internal sealed partial class SlideDeckJsonContext : JsonSerializerContext;
|
||||||
@@ -7,7 +7,7 @@ namespace AIStudio.Tools.PowerPoint;
|
|||||||
|
|
||||||
internal sealed partial record SlideDeckSpec
|
internal sealed partial record SlideDeckSpec
|
||||||
{
|
{
|
||||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
internal static readonly JsonSerializerOptions JSON_OPTIONS = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||||
PropertyNameCaseInsensitive = true,
|
PropertyNameCaseInsensitive = true,
|
||||||
@@ -15,7 +15,8 @@ internal sealed partial record SlideDeckSpec
|
|||||||
AllowTrailingCommas = true,
|
AllowTrailingCommas = true,
|
||||||
ReadCommentHandling = JsonCommentHandling.Skip,
|
ReadCommentHandling = JsonCommentHandling.Skip,
|
||||||
MaxDepth = 16,
|
MaxDepth = 16,
|
||||||
};
|
TypeInfoResolver = SlideDeckJsonContext.Default,
|
||||||
|
}.AsReadOnly();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The deepest list level a paragraph may have; PowerPoint knows nine, starting at 0.
|
/// The deepest list level a paragraph may have; PowerPoint knows nine, starting at 0.
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace AIStudio.Tools.Services;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The contracts with which System.Text.Json writes what the Assistant Builder hands to its models, built at compile
|
||||||
|
/// time.
|
||||||
|
/// </summary>
|
||||||
|
[JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)]
|
||||||
|
[JsonSerializable(typeof(AssistantBuilderDraftPromptData))]
|
||||||
|
[JsonSerializable(typeof(AssistantBuilderGenerationPromptData))]
|
||||||
|
[JsonSerializable(typeof(AssistantBuilderLauncherPromptData))]
|
||||||
|
[JsonSerializable(typeof(AssistantBuilderRevisionPromptData))]
|
||||||
|
internal sealed partial class AssistantBuilderPromptJsonContext : JsonSerializerContext;
|
||||||
@@ -19,11 +19,12 @@ public sealed class AssistantPluginGenerationService(ToolRegistry toolRegistry,
|
|||||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(AssistantPluginGenerationService).Namespace, nameof(AssistantPluginGenerationService));
|
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(AssistantPluginGenerationService).Namespace, nameof(AssistantPluginGenerationService));
|
||||||
|
|
||||||
// Internal rather than private, so that a test can check the JSON the models get:
|
// Internal rather than private, so that a test can check the JSON the models get:
|
||||||
internal static readonly JsonSerializerOptions UNTRUSTED_PROMPT_JSON_OPTIONS = new()
|
internal static readonly JsonSerializerOptions UNTRUSTED_PROMPT_JSON_OPTIONS = new JsonSerializerOptions
|
||||||
{
|
{
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||||
WriteIndented = true,
|
WriteIndented = true,
|
||||||
};
|
TypeInfoResolver = AssistantBuilderPromptJsonContext.Default,
|
||||||
|
}.AsReadOnly();
|
||||||
|
|
||||||
private const string LUA_RESPONSE_SCHEMA_PATH = "Assistants/Builder/AssistantBuilderLuaResponse.schema.json";
|
private const string LUA_RESPONSE_SCHEMA_PATH = "Assistants/Builder/AssistantBuilderLuaResponse.schema.json";
|
||||||
private const string DEFAULT_VERSION = "1.0.0";
|
private const string DEFAULT_VERSION = "1.0.0";
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public sealed class JsonContractTests
|
|||||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingHashed))]
|
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingHashed))]
|
||||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingAnswers))]
|
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingAnswers))]
|
||||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ModelAnswers))]
|
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ModelAnswers))]
|
||||||
|
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ModelPrompts))]
|
||||||
public void TheContractsMatchThoseOfReflection(JsonTestRoot root)
|
public void TheContractsMatchThoseOfReflection(JsonTestRoot root)
|
||||||
{
|
{
|
||||||
var baseline = JsonReflectionBaseline.Of(root.Options);
|
var baseline = JsonReflectionBaseline.Of(root.Options);
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ public sealed class JsonCoverageTests
|
|||||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingStored))]
|
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingStored))]
|
||||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingHashed))]
|
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingHashed))]
|
||||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingAnswers))]
|
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingAnswers))]
|
||||||
|
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ModelAnswers))]
|
||||||
|
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ModelPrompts))]
|
||||||
public void EveryContractComesFromSourceGeneration(JsonTestRoot root)
|
public void EveryContractComesFromSourceGeneration(JsonTestRoot root)
|
||||||
{
|
{
|
||||||
var typesWithoutGeneratedContract = JsonTypeGraph.Collect(root.Type, root.Options)
|
var typesWithoutGeneratedContract = JsonTypeGraph.Collect(root.Type, root.Options)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using AIStudio.Assistants.ERI;
|
|||||||
using AIStudio.Assistants.PromptOptimizer;
|
using AIStudio.Assistants.PromptOptimizer;
|
||||||
using AIStudio.Assistants.SWOTAnalysis;
|
using AIStudio.Assistants.SWOTAnalysis;
|
||||||
using AIStudio.Tools.PowerPoint;
|
using AIStudio.Tools.PowerPoint;
|
||||||
|
using AIStudio.Tools.Services;
|
||||||
|
|
||||||
namespace AIStudio.Tests.Serialization;
|
namespace AIStudio.Tests.Serialization;
|
||||||
|
|
||||||
@@ -33,4 +34,20 @@ public static partial class JsonTestRoots
|
|||||||
yield return Case(new(typeof(ERIServerFileList), ERIServerFileList.JSON_OPTIONS));
|
yield return Case(new(typeof(ERIServerFileList), ERIServerFileList.JSON_OPTIONS));
|
||||||
yield return Case(new(typeof(SlideDeckSpec.DeckDto), SlideDeckSpec.JSON_OPTIONS));
|
yield return Case(new(typeof(SlideDeckSpec.DeckDto), SlideDeckSpec.JSON_OPTIONS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The JSON which the Assistant Builder and the moderation of a SWOT analysis put into their prompts.
|
||||||
|
/// </summary>
|
||||||
|
public static IEnumerable<TestCaseData> ModelPrompts()
|
||||||
|
{
|
||||||
|
TestHost.PrepareStaticState();
|
||||||
|
|
||||||
|
var untrusted = AssistantPluginGenerationService.UNTRUSTED_PROMPT_JSON_OPTIONS;
|
||||||
|
yield return Case(new(typeof(AssistantBuilderDraftPromptData), untrusted));
|
||||||
|
yield return Case(new(typeof(AssistantBuilderGenerationPromptData), untrusted));
|
||||||
|
yield return Case(new(typeof(AssistantBuilderLauncherPromptData), untrusted));
|
||||||
|
yield return Case(new(typeof(AssistantBuilderRevisionPromptData), untrusted));
|
||||||
|
|
||||||
|
yield return Case(new(typeof(Dictionary<string, SwotModerationCategoryInput>), SwotAnalysisModeration.JSON_OPTIONS));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user