mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-05 12:27:21 +00:00
Replaced the anonymous JSON shapes of the Assistant Builder and the SWOT moderation with records
This commit is contained in:
15 files changed
+336
-43
No files matched your search
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"assistant_description": "Summarizes \u003Cmeeting notes\u003E of any Gr\u00F6\u00DFe.",
|
||||
"category": null,
|
||||
"assistant_title": "Meeting \u0022Notes\u0022 Summary",
|
||||
"typical_input": null,
|
||||
"expected_output": "A short summary \u0026 a list of decisions.",
|
||||
"requested_ui_input_components": null,
|
||||
"output_language": "German",
|
||||
"allow_ai_studio_profiles": true,
|
||||
"extra_rules": null,
|
||||
"example_request": "Summarize the notes of Monday\u0027s meeting.",
|
||||
"chat_launch": null
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"approved_assistant_draft": "# Assistant Draft\n## Name\nMeeting \u0022Notes\u0022 Summary\n## Description\nSummarizes \u003Cnotes\u003E of any Gr\u00F6\u00DFe.",
|
||||
"review_notes": null
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"approved_assistant_draft": "# Assistant Draft\n## Name\nMeeting \u0022Notes\u0022 Summary\n## Description\nSummarizes \u003Cnotes\u003E of any Gr\u00F6\u00DFe.",
|
||||
"review_notes": "Keep the title short.",
|
||||
"chat_launch": {
|
||||
"workspace_name": "Workspace \u003CGr\u00F6\u00DFe\u003E",
|
||||
"provider_id": "provider id sample",
|
||||
"profile_id": "00000000-0000-0000-0000-000000000000",
|
||||
"chat_template_id": null,
|
||||
"data_source_ids": [
|
||||
"data source 1",
|
||||
"data source 2"
|
||||
],
|
||||
"tool_ids": null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"plugin_id": "6f1c3a52-9d4e-4b8a-a2f7-0c5e81d94b36",
|
||||
"plugin_name": "Meeting Notes",
|
||||
"assistant_title": "Meeting \u0022Notes\u0022 Summary",
|
||||
"change_request": "Add a \u003Ctone\u003E dropdown with \u201Eformal\u201C and \u201Ecasual\u201C.",
|
||||
"test_context": null
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
Reconcile these preliminary results of the four SWOT categories. Then write the overall assessment
|
||||
and the prioritized actions.
|
||||
|
||||
<analysis-goal>
|
||||
Decide whether the company should grow to a new Größe.
|
||||
</analysis-goal>
|
||||
|
||||
<analysis-focus>
|
||||
No additional analysis focus was provided.
|
||||
</analysis-focus>
|
||||
|
||||
<category-results>
|
||||
{
|
||||
"strengths": {
|
||||
"empty_message": "",
|
||||
"findings": [
|
||||
{
|
||||
"factor_id": "S1",
|
||||
"summary": "A loyal \u0022core\u0022 team",
|
||||
"explanation": "The team stayed together for years."
|
||||
},
|
||||
{
|
||||
"factor_id": "S2",
|
||||
"summary": "Low costs",
|
||||
"explanation": "Costs are \u003C10 %\u003E below the market."
|
||||
}
|
||||
]
|
||||
},
|
||||
"weaknesses": {
|
||||
"empty_message": "",
|
||||
"findings": [
|
||||
{
|
||||
"factor_id": "W1",
|
||||
"summary": "Small Gr\u00F6\u00DFe",
|
||||
"explanation": "The company has only twelve employees."
|
||||
}
|
||||
]
|
||||
},
|
||||
"opportunities": {
|
||||
"empty_message": "The sources name no external opportunities.",
|
||||
"findings": []
|
||||
},
|
||||
"threats": {
|
||||
"empty_message": "",
|
||||
"findings": [
|
||||
{
|
||||
"factor_id": "T1",
|
||||
"summary": "New competitors",
|
||||
"explanation": "Two competitors entered the market."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
</category-results>
|
||||
|
||||
<shared-research>
|
||||
The market grew by 8 % in the "last" year.
|
||||
</shared-research>
|
||||
@@ -0,0 +1,66 @@
|
||||
using AIStudio.Assistants.SWOTAnalysis;
|
||||
using AIStudio.Tools.Services;
|
||||
|
||||
namespace AIStudio.Tests.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Synthetic inputs for the JSON which the Assistant Builder and the SWOT analysis put into their prompts.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The texts carry umlauts, quotes, and angle brackets, because the encoder of the options escapes them. The values of
|
||||
/// the Assistant Builder are the ones its prompts get after trimming: a field the user left empty is null.
|
||||
/// </remarks>
|
||||
internal static class PromptDataSamples
|
||||
{
|
||||
internal const string DESCRIPTION = "Summarizes <meeting notes> of any Größe.";
|
||||
|
||||
internal const string TITLE = "Meeting \"Notes\" Summary";
|
||||
|
||||
internal const string EXPECTED_OUTPUT = "A short summary & a list of decisions.";
|
||||
|
||||
internal const string OUTPUT_LANGUAGE = "German";
|
||||
|
||||
internal const string EXAMPLE_REQUEST = "Summarize the notes of Monday's meeting.";
|
||||
|
||||
internal const string DRAFT = "# Assistant Draft\n## Name\nMeeting \"Notes\" Summary\n## Description\nSummarizes <notes> of any Größe.";
|
||||
|
||||
internal const string REVIEW_NOTES = "Keep the title short.";
|
||||
|
||||
internal const string PLUGIN_NAME = "Meeting Notes";
|
||||
|
||||
internal const string CHANGE_REQUEST = "Add a <tone> dropdown with „formal“ and „casual“.";
|
||||
|
||||
internal const string SWOT_GOAL = "Decide whether the company should grow to a new Größe.";
|
||||
|
||||
internal const string SWOT_RESEARCH = "The market grew by 8 % in the \"last\" year.";
|
||||
|
||||
internal static readonly Guid PLUGIN_ID = Guid.Parse("6f1c3a52-9d4e-4b8a-a2f7-0c5e81d94b36");
|
||||
|
||||
internal static AssistantBuilderChatLaunchRequest ChatLaunch() => new(
|
||||
"Workspace <Größe>",
|
||||
"provider id sample",
|
||||
Guid.Empty.ToString(),
|
||||
null,
|
||||
["data source 1", "data source 2"],
|
||||
null);
|
||||
|
||||
internal static IReadOnlyDictionary<SwotAnalysisCategory, SwotCategoryAnalysisResult> SwotCategories() => new Dictionary<SwotAnalysisCategory, SwotCategoryAnalysisResult>
|
||||
{
|
||||
[SwotAnalysisCategory.STRENGTHS] = Category(string.Empty, Finding("A loyal \"core\" team", "The team stayed together for years."), Finding("Low costs", "Costs are <10 %> below the market.")),
|
||||
[SwotAnalysisCategory.WEAKNESSES] = Category(string.Empty, Finding("Small Größe", "The company has only twelve employees.")),
|
||||
[SwotAnalysisCategory.OPPORTUNITIES] = Category("The sources name no external opportunities."),
|
||||
[SwotAnalysisCategory.THREATS] = Category(string.Empty, Finding("New competitors", "Two competitors entered the market.")),
|
||||
};
|
||||
|
||||
private static SwotCategoryAnalysisResult Category(string emptyMessage, params List<SwotFinding> findings) => new()
|
||||
{
|
||||
EmptyMessage = emptyMessage,
|
||||
Findings = findings,
|
||||
};
|
||||
|
||||
private static SwotFinding Finding(string summary, string explanation) => new()
|
||||
{
|
||||
Summary = summary,
|
||||
Explanation = explanation,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System.Text.Json;
|
||||
|
||||
using AIStudio.Assistants.SWOTAnalysis;
|
||||
using AIStudio.Tools.Services;
|
||||
|
||||
namespace AIStudio.Tests.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Checks that the Assistant Builder and the moderation of a SWOT analysis send their models the same JSON as before.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The files in the folder Fixtures were written by the anonymous shapes which the records replaced. A model reads the
|
||||
/// JSON of a prompt as it is, so a field under another name or one which went missing changes what it does. Both
|
||||
/// write their JSON indented, with the line breaks of the OS, so the comparison ignores which line breaks they are.
|
||||
/// </remarks>
|
||||
[TestFixture]
|
||||
public sealed class PromptDataShapeTests
|
||||
{
|
||||
private static IEnumerable<TestCaseData> AssistantBuilderData()
|
||||
{
|
||||
yield return Case("assistant-builder-draft-data.json", () => Serialize(new AssistantBuilderDraftPromptData(
|
||||
PromptDataSamples.DESCRIPTION,
|
||||
null,
|
||||
PromptDataSamples.TITLE,
|
||||
null,
|
||||
PromptDataSamples.EXPECTED_OUTPUT,
|
||||
null,
|
||||
PromptDataSamples.OUTPUT_LANGUAGE,
|
||||
true,
|
||||
null,
|
||||
PromptDataSamples.EXAMPLE_REQUEST,
|
||||
null)));
|
||||
|
||||
yield return Case("assistant-builder-generation-data.json", () => Serialize(new AssistantBuilderGenerationPromptData(PromptDataSamples.DRAFT, null)));
|
||||
yield return Case("assistant-builder-launcher-data.json", () => Serialize(new AssistantBuilderLauncherPromptData(PromptDataSamples.DRAFT, PromptDataSamples.REVIEW_NOTES, PromptDataSamples.ChatLaunch())));
|
||||
yield return Case("assistant-builder-revision-data.json", () => Serialize(new AssistantBuilderRevisionPromptData(
|
||||
PromptDataSamples.PLUGIN_ID,
|
||||
PromptDataSamples.PLUGIN_NAME,
|
||||
PromptDataSamples.TITLE,
|
||||
PromptDataSamples.CHANGE_REQUEST,
|
||||
null)));
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(AssistantBuilderData))]
|
||||
public void TheAssistantBuilderSendsTheSameJsonAsBefore(string fileName, Func<string> serialize) => Assert.That(Normalized(serialize()), Is.EqualTo(Normalized(JsonGoldenFileTests.ReadFixture(fileName))));
|
||||
|
||||
[Test]
|
||||
public void TheModeratorOfASwotAnalysisGetsTheSameRequestAsBefore()
|
||||
{
|
||||
var request = SwotAnalysisModeration.BuildUserRequest(PromptDataSamples.SwotCategories(), PromptDataSamples.SWOT_GOAL, string.Empty, PromptDataSamples.SWOT_RESEARCH);
|
||||
Assert.That(Normalized(request), Is.EqualTo(Normalized(JsonGoldenFileTests.ReadFixture("swot-moderation-request.txt"))));
|
||||
}
|
||||
|
||||
private static TestCaseData Case(string fileName, Func<string> serialize) => new TestCaseData(fileName, serialize).SetArgDisplayNames(fileName);
|
||||
|
||||
private static string Serialize<T>(T value) => JsonSerializer.Serialize(value, AssistantPluginGenerationService.UNTRUSTED_PROMPT_JSON_OPTIONS);
|
||||
|
||||
private static string Normalized(string text) => text.ReplaceLineEndings("\n");
|
||||
}
|
||||
Reference in new issue
Block a user