mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-03 23:07:21 +00:00
Added tests which guard the JSON of visual briefings and model answers before source generation
This commit is contained in:
22 files changed
+1102
-12
No files matched your search
@@ -19,7 +19,7 @@ public abstract class AgentBase(ILogger<AgentBase> logger, SettingsManager setti
|
||||
Time = DateTimeOffset.UtcNow,
|
||||
};
|
||||
|
||||
protected static readonly JsonSerializerOptions JSON_SERIALIZER_OPTIONS = new()
|
||||
internal static readonly JsonSerializerOptions JSON_SERIALIZER_OPTIONS = new()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||
};
|
||||
|
||||
@@ -14,7 +14,7 @@ internal sealed class LauncherTextsResponse
|
||||
{
|
||||
public const string SCHEMA_VERSION_VALUE = "assistant_builder_launcher_texts_v1";
|
||||
|
||||
private static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||
AllowTrailingCommas = false,
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace AIStudio.Assistants.Builder;
|
||||
|
||||
internal sealed partial class LuaResponse
|
||||
{
|
||||
private static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||
AllowTrailingCommas = false,
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace AIStudio.Assistants.ERI;
|
||||
/// </remarks>
|
||||
internal sealed class ERIServerFileList
|
||||
{
|
||||
private static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
AllowTrailingCommas = false,
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace AIStudio.Assistants.PromptOptimizer;
|
||||
|
||||
public partial class AssistantPromptOptimizer : AssistantBaseCore<SettingsDialogPromptOptimizer>
|
||||
{
|
||||
private static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace AIStudio.Assistants.SWOTAnalysis;
|
||||
/// </summary>
|
||||
internal static class SwotModelAnswer
|
||||
{
|
||||
private static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
AllowTrailingCommas = true,
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace AIStudio.Tools.PowerPoint;
|
||||
|
||||
internal sealed partial record SlideDeckSpec
|
||||
{
|
||||
private static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
internal static readonly JsonSerializerOptions JSON_OPTIONS = new()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||
PropertyNameCaseInsensitive = true,
|
||||
@@ -158,17 +158,18 @@ internal sealed partial record SlideDeckSpec
|
||||
private static string Clean(string? text) => text?.Trim() ?? string.Empty;
|
||||
|
||||
//
|
||||
// What the model writes, before anything is checked. Every value may be missing or null.
|
||||
// What the model writes, before anything is checked. Every value may be missing or null. Internal
|
||||
// rather than private, so that the JSON context of the deck can name them:
|
||||
//
|
||||
|
||||
private sealed class DeckDto
|
||||
internal sealed class DeckDto
|
||||
{
|
||||
public string? Title { get; set; }
|
||||
|
||||
public List<SlideDto?>? Slides { get; set; }
|
||||
}
|
||||
|
||||
private sealed class SlideDto
|
||||
internal sealed class SlideDto
|
||||
{
|
||||
public int? TemplateSlide { get; set; }
|
||||
|
||||
@@ -191,7 +192,7 @@ internal sealed partial record SlideDeckSpec
|
||||
public JsonElement? Remove { get; set; }
|
||||
}
|
||||
|
||||
private sealed class TableDto
|
||||
internal sealed class TableDto
|
||||
{
|
||||
public List<JsonElement>? Headers { get; set; }
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"buildVersion": 41,
|
||||
"buildId": "00000000-0000-4000-8000-000000000002",
|
||||
"operationId": "00000000-0000-4000-8000-000000000003",
|
||||
"briefingId": "00000000-0000-4000-8000-000000000004",
|
||||
"mode": "CHANGE_DESIGN",
|
||||
"parentRevisionId": "00000000-0000-4000-8000-000000000005",
|
||||
"instruction": "instruction sample 6",
|
||||
"status": "COMPLETED",
|
||||
"stages": [
|
||||
{
|
||||
"stage": "EVIDENCE",
|
||||
"status": "RUNNING",
|
||||
"inputFingerprint": "inputFingerprint sample 7",
|
||||
"startedAtUtc": "2026-10-29T12:38:15+01:00",
|
||||
"finishedAtUtc": "2026-10-29T12:39:15+01:00",
|
||||
"attempts": 50,
|
||||
"outputHash": "outputHash sample 11",
|
||||
"failure": {
|
||||
"code": "PROVIDER_NOT_SELECTED",
|
||||
"stage": "EVIDENCE",
|
||||
"userMessage": "userMessage sample 12",
|
||||
"technicalDetails": "technicalDetails sample 13",
|
||||
"validationRule": "JSON_INVALID",
|
||||
"structuredResponse": {
|
||||
"issueKind": "EMPTY_RESPONSE",
|
||||
"envelope": "MARKDOWN_JSON_BLOCK",
|
||||
"candidateIndex": 54,
|
||||
"candidateCount": 55,
|
||||
"jsonPath": "/samples/jsonPath-16.txt",
|
||||
"lineNumber": 4000000017,
|
||||
"bytePositionInLine": 4000000018,
|
||||
"fieldName": "fieldName sample 19",
|
||||
"expected": "expected sample 20"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"stage": "EVIDENCE",
|
||||
"status": "RUNNING",
|
||||
"inputFingerprint": "inputFingerprint sample 21",
|
||||
"startedAtUtc": "2026-10-29T12:52:15+01:00",
|
||||
"finishedAtUtc": "2026-10-29T12:53:15+01:00",
|
||||
"attempts": 64,
|
||||
"outputHash": "outputHash sample 25",
|
||||
"failure": {
|
||||
"code": "PROVIDER_NOT_SELECTED",
|
||||
"stage": "EVIDENCE",
|
||||
"userMessage": "userMessage sample 26",
|
||||
"technicalDetails": "technicalDetails sample 27",
|
||||
"validationRule": "JSON_INVALID",
|
||||
"structuredResponse": {
|
||||
"issueKind": "EMPTY_RESPONSE",
|
||||
"envelope": "MARKDOWN_JSON_BLOCK",
|
||||
"candidateIndex": 68,
|
||||
"candidateCount": 69,
|
||||
"jsonPath": "/samples/jsonPath-30.txt",
|
||||
"lineNumber": 4000000031,
|
||||
"bytePositionInLine": 4000000032,
|
||||
"fieldName": "fieldName sample 33",
|
||||
"expected": "expected sample 34"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"contentArtifactId": "00000000-0000-4000-8000-000000000035",
|
||||
"evidenceArtifactId": "00000000-0000-4000-8000-000000000036",
|
||||
"planArtifactId": "00000000-0000-4000-8000-000000000037",
|
||||
"presentationArtifactId": "00000000-0000-4000-8000-000000000038",
|
||||
"revisionId": "00000000-0000-4000-8000-000000000039",
|
||||
"committedRevisionId": "00000000-0000-4000-8000-000000000040",
|
||||
"inputFingerprint": "inputFingerprint sample 41",
|
||||
"sourceFingerprint": "sourceFingerprint sample 42",
|
||||
"contentContractVersion": 83,
|
||||
"evidenceContractVersion": 84,
|
||||
"planContractVersion": 85,
|
||||
"designContractVersion": 86,
|
||||
"providerFamily": "providerFamily sample 47",
|
||||
"model": "model sample 48",
|
||||
"createdAtUtc": "2026-10-29T13:19:15+01:00",
|
||||
"updatedAtUtc": "2026-10-29T13:20:15+01:00",
|
||||
"failure": {
|
||||
"code": "PROVIDER_NOT_SELECTED",
|
||||
"stage": "EVIDENCE",
|
||||
"userMessage": "userMessage sample 51",
|
||||
"technicalDetails": "technicalDetails sample 52",
|
||||
"validationRule": "JSON_INVALID",
|
||||
"structuredResponse": {
|
||||
"issueKind": "EMPTY_RESPONSE",
|
||||
"envelope": "MARKDOWN_JSON_BLOCK",
|
||||
"candidateIndex": 43,
|
||||
"candidateCount": 44,
|
||||
"jsonPath": "/samples/jsonPath-55.txt",
|
||||
"lineNumber": 4000000056,
|
||||
"bytePositionInLine": 4000000057,
|
||||
"fieldName": "fieldName sample 58",
|
||||
"expected": "expected sample 59"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"slots":{"overview-title":"Text of overview-title, with Gr\u00F6\u00DFe and \u20AC","overview-summary":"Text of overview-summary, with Gr\u00F6\u00DFe and \u20AC","chart-line-title":"Text of chart-line-title, with Gr\u00F6\u00DFe and \u20AC","chart-line-caption":"Text of chart-line-caption, with Gr\u00F6\u00DFe and \u20AC","chart-area-title":"Text of chart-area-title, with Gr\u00F6\u00DFe and \u20AC","chart-area-caption":"Text of chart-area-caption, with Gr\u00F6\u00DFe and \u20AC","chart-bar-title":"Text of chart-bar-title, with Gr\u00F6\u00DFe and \u20AC","chart-bar-caption":"Text of chart-bar-caption, with Gr\u00F6\u00DFe and \u20AC","chart-stacked_bar-title":"Text of chart-stacked_bar-title, with Gr\u00F6\u00DFe and \u20AC","chart-stacked_bar-caption":"Text of chart-stacked_bar-caption, with Gr\u00F6\u00DFe and \u20AC","chart-scatter-title":"Text of chart-scatter-title, with Gr\u00F6\u00DFe and \u20AC","chart-scatter-caption":"Text of chart-scatter-caption, with Gr\u00F6\u00DFe and \u20AC","chart-pie-title":"Text of chart-pie-title, with Gr\u00F6\u00DFe and \u20AC","chart-pie-caption":"Text of chart-pie-caption, with Gr\u00F6\u00DFe and \u20AC","chart-donut-title":"Text of chart-donut-title, with Gr\u00F6\u00DFe and \u20AC","chart-donut-caption":"Text of chart-donut-caption, with Gr\u00F6\u00DFe and \u20AC","chart-radar-title":"Text of chart-radar-title, with Gr\u00F6\u00DFe and \u20AC","chart-radar-caption":"Text of chart-radar-caption, with Gr\u00F6\u00DFe and \u20AC","simulation-title":"Text of simulation-title, with Gr\u00F6\u00DFe and \u20AC","simulation-summary":"Text of simulation-summary, with Gr\u00F6\u00DFe and \u20AC","simulation-result":"Text of simulation-result, with Gr\u00F6\u00DFe and \u20AC"},"charts":{"chart-line":{"color":["#236A50","#F2D264","#79AE90","#C97857","#4E7894","#9B6B8F"],"backgroundColor":"transparent","textStyle":{"color":"#172A24","fontFamily":"system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif"},"tooltip":{"trigger":"axis","borderColor":"#D6E2DC","backgroundColor":"#FFFEFA","textStyle":{"color":"#172A24"}},"legend":{"show":true,"top":0,"textStyle":{"color":"#4F635B"}},"grid":{"left":8,"right":16,"top":48,"bottom":8,"containLabel":true},"xAxis":{"type":"category","data":["Q1","Q2","Q3"],"axisLine":{"lineStyle":{"color":"#B8C9C0"}},"axisTick":{"show":false},"axisLabel":{"color":"#5E7169"}},"yAxis":{"type":"value","axisLine":{"show":false},"axisTick":{"show":false},"axisLabel":{"color":"#5E7169"},"splitLine":{"lineStyle":{"color":"#E1EAE5"}}},"radar":null,"series":[{"name":"Revenue","type":"line","stack":null,"areaStyle":null,"smooth":true,"showSymbol":false,"symbolSize":6,"itemStyle":null,"data":[12.5,14,9.75]},{"name":"Costs","type":"line","stack":null,"areaStyle":null,"smooth":true,"showSymbol":false,"symbolSize":6,"itemStyle":null,"data":[8,7.25,10]}]},"chart-area":{"color":["#236A50","#F2D264","#79AE90","#C97857","#4E7894","#9B6B8F"],"backgroundColor":"transparent","textStyle":{"color":"#172A24","fontFamily":"system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif"},"tooltip":{"trigger":"axis","borderColor":"#D6E2DC","backgroundColor":"#FFFEFA","textStyle":{"color":"#172A24"}},"legend":{"show":true,"top":0,"textStyle":{"color":"#4F635B"}},"grid":{"left":8,"right":16,"top":48,"bottom":8,"containLabel":true},"xAxis":{"type":"category","data":["Q1","Q2","Q3"],"axisLine":{"lineStyle":{"color":"#B8C9C0"}},"axisTick":{"show":false},"axisLabel":{"color":"#5E7169"}},"yAxis":{"type":"value","axisLine":{"show":false},"axisTick":{"show":false},"axisLabel":{"color":"#5E7169"},"splitLine":{"lineStyle":{"color":"#E1EAE5"}}},"radar":null,"series":[{"name":"Revenue","type":"line","stack":null,"areaStyle":{"opacity":0.18},"smooth":true,"showSymbol":false,"symbolSize":6,"itemStyle":null,"data":[12.5,14,9.75]},{"name":"Costs","type":"line","stack":null,"areaStyle":{"opacity":0.18},"smooth":true,"showSymbol":false,"symbolSize":6,"itemStyle":null,"data":[8,7.25,10]}]},"chart-bar":{"color":["#236A50","#F2D264","#79AE90","#C97857","#4E7894","#9B6B8F"],"backgroundColor":"transparent","textStyle":{"color":"#172A24","fontFamily":"system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif"},"tooltip":{"trigger":"axis","borderColor":"#D6E2DC","backgroundColor":"#FFFEFA","textStyle":{"color":"#172A24"}},"legend":{"show":true,"top":0,"textStyle":{"color":"#4F635B"}},"grid":{"left":8,"right":16,"top":48,"bottom":8,"containLabel":true},"xAxis":{"type":"category","data":["Q1","Q2","Q3"],"axisLine":{"lineStyle":{"color":"#B8C9C0"}},"axisTick":{"show":false},"axisLabel":{"color":"#5E7169"}},"yAxis":{"type":"value","axisLine":{"show":false},"axisTick":{"show":false},"axisLabel":{"color":"#5E7169"},"splitLine":{"lineStyle":{"color":"#E1EAE5"}}},"radar":null,"series":[{"name":"Revenue","type":"bar","stack":null,"areaStyle":null,"smooth":false,"showSymbol":false,"symbolSize":6,"itemStyle":{"borderRadius":[6,6,0,0]},"data":[12.5,14,9.75]},{"name":"Costs","type":"bar","stLine truncated
|
||||
@@ -0,0 +1,188 @@
|
||||
{
|
||||
"artifactVersion": 41,
|
||||
"contractVersion": 42,
|
||||
"artifactId": "00000000-0000-4000-8000-000000000003",
|
||||
"createdAtUtc": "2026-10-29T12:34:15+01:00",
|
||||
"payloadHash": "payloadHash sample 5",
|
||||
"data": {
|
||||
"sample": 6,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
},
|
||||
"slots": [
|
||||
{
|
||||
"slotId": "slotId sample 7",
|
||||
"value": {
|
||||
"sample": 8,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"slotId": "slotId sample 9",
|
||||
"value": {
|
||||
"sample": 10,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
}
|
||||
}
|
||||
],
|
||||
"charts": [
|
||||
{
|
||||
"componentId": "componentId sample 11",
|
||||
"kind": "AREA",
|
||||
"categories": [
|
||||
"categories sample 12",
|
||||
"categories sample 13"
|
||||
],
|
||||
"series": [
|
||||
{
|
||||
"name": "name sample 14",
|
||||
"values": [
|
||||
3.75,
|
||||
4.75
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "name sample 15",
|
||||
"values": [
|
||||
3.75,
|
||||
4.75
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"componentId": "componentId sample 16",
|
||||
"kind": "AREA",
|
||||
"categories": [
|
||||
"categories sample 17",
|
||||
"categories sample 18"
|
||||
],
|
||||
"series": [
|
||||
{
|
||||
"name": "name sample 19",
|
||||
"values": [
|
||||
3.75,
|
||||
4.75
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "name sample 20",
|
||||
"values": [
|
||||
3.75,
|
||||
4.75
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"controls": [
|
||||
{
|
||||
"controlId": "controlId sample 21",
|
||||
"componentId": "componentId sample 22",
|
||||
"kind": "FILTER",
|
||||
"initialValue": {
|
||||
"sample": 23,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
},
|
||||
"options": [
|
||||
{
|
||||
"value": "value sample 24",
|
||||
"label": "label sample 25"
|
||||
},
|
||||
{
|
||||
"value": "value sample 26",
|
||||
"label": "label sample 27"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"controlId": "controlId sample 28",
|
||||
"componentId": "componentId sample 29",
|
||||
"kind": "FILTER",
|
||||
"initialValue": {
|
||||
"sample": 30,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
},
|
||||
"options": [
|
||||
{
|
||||
"value": "value sample 31",
|
||||
"label": "label sample 32"
|
||||
},
|
||||
{
|
||||
"value": "value sample 33",
|
||||
"label": "label sample 34"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"formulas": [
|
||||
{
|
||||
"componentId": "componentId sample 35",
|
||||
"outputSlotId": "outputSlotId sample 36",
|
||||
"formula": {
|
||||
"formulaVersion": 77,
|
||||
"op": "op sample 38",
|
||||
"path": "/samples/path-39.txt",
|
||||
"value": {
|
||||
"sample": 40,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
},
|
||||
"args": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"componentId": "componentId sample 41",
|
||||
"outputSlotId": "outputSlotId sample 42",
|
||||
"formula": {
|
||||
"formulaVersion": 83,
|
||||
"op": "op sample 44",
|
||||
"path": "/samples/path-45.txt",
|
||||
"value": {
|
||||
"sample": 46,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
},
|
||||
"args": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"accessibilityTexts": {
|
||||
"accessibilityTextsKey sample 47": "accessibilityTexts sample 48",
|
||||
"accessibilityTextsKey sample 49": "accessibilityTexts sample 50"
|
||||
},
|
||||
"sourceReferences": {
|
||||
"sourceReferencesKey sample 51": [
|
||||
"sourceReferences sample 52",
|
||||
"sourceReferences sample 53"
|
||||
],
|
||||
"sourceReferencesKey sample 54": [
|
||||
"sourceReferences sample 55",
|
||||
"sourceReferences sample 56"
|
||||
]
|
||||
},
|
||||
"resetLabel": "resetLabel sample 57",
|
||||
"sourceCoverage": [
|
||||
{
|
||||
"sourceId": "sourceId sample 58",
|
||||
"coverage": "CONTEXTUAL",
|
||||
"reason": "reason sample 59"
|
||||
},
|
||||
{
|
||||
"sourceId": "sourceId sample 60",
|
||||
"coverage": "CONTEXTUAL",
|
||||
"reason": "reason sample 61"
|
||||
}
|
||||
],
|
||||
"assetPlan": [
|
||||
{
|
||||
"assetId": "assetId sample 62",
|
||||
"description": "description sample 63",
|
||||
"altText": "altText sample 64"
|
||||
},
|
||||
{
|
||||
"assetId": "assetId sample 65",
|
||||
"description": "description sample 66",
|
||||
"altText": "altText sample 67"
|
||||
}
|
||||
],
|
||||
"structuralSignature": "structuralSignature sample 68",
|
||||
"model": "model sample 69"
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
{
|
||||
"artifactVersion": 41,
|
||||
"contractVersion": 42,
|
||||
"artifactId": "00000000-0000-4000-8000-000000000003",
|
||||
"createdAtUtc": "2026-10-29T12:34:15+01:00",
|
||||
"payloadHash": "payloadHash sample 5",
|
||||
"facts": [
|
||||
{
|
||||
"evidenceId": "evidenceId sample 6",
|
||||
"statement": "statement sample 7",
|
||||
"sourceIds": [
|
||||
"sourceIds sample 8",
|
||||
"sourceIds sample 9"
|
||||
]
|
||||
},
|
||||
{
|
||||
"evidenceId": "evidenceId sample 10",
|
||||
"statement": "statement sample 11",
|
||||
"sourceIds": [
|
||||
"sourceIds sample 12",
|
||||
"sourceIds sample 13"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metrics": [
|
||||
{
|
||||
"evidenceId": "evidenceId sample 14",
|
||||
"label": "label sample 15",
|
||||
"value": 3.75,
|
||||
"unit": "unit sample 16",
|
||||
"sourceIds": [
|
||||
"sourceIds sample 17",
|
||||
"sourceIds sample 18"
|
||||
]
|
||||
},
|
||||
{
|
||||
"evidenceId": "evidenceId sample 19",
|
||||
"label": "label sample 20",
|
||||
"value": 3.75,
|
||||
"unit": "unit sample 21",
|
||||
"sourceIds": [
|
||||
"sourceIds sample 22",
|
||||
"sourceIds sample 23"
|
||||
]
|
||||
}
|
||||
],
|
||||
"tables": [
|
||||
{
|
||||
"evidenceId": "evidenceId sample 24",
|
||||
"title": "title sample 25",
|
||||
"columns": [
|
||||
"columns sample 26",
|
||||
"columns sample 27"
|
||||
],
|
||||
"rows": [
|
||||
[
|
||||
{
|
||||
"sample": 28,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
},
|
||||
{
|
||||
"sample": 29,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"sample": 30,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
},
|
||||
{
|
||||
"sample": 31,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
}
|
||||
]
|
||||
],
|
||||
"sourceIds": [
|
||||
"sourceIds sample 32",
|
||||
"sourceIds sample 33"
|
||||
]
|
||||
},
|
||||
{
|
||||
"evidenceId": "evidenceId sample 34",
|
||||
"title": "title sample 35",
|
||||
"columns": [
|
||||
"columns sample 36",
|
||||
"columns sample 37"
|
||||
],
|
||||
"rows": [
|
||||
[
|
||||
{
|
||||
"sample": 38,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
},
|
||||
{
|
||||
"sample": 39,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"sample": 40,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
},
|
||||
{
|
||||
"sample": 41,
|
||||
"text": "Gr\u00F6\u00DFe"
|
||||
}
|
||||
]
|
||||
],
|
||||
"sourceIds": [
|
||||
"sourceIds sample 42",
|
||||
"sourceIds sample 43"
|
||||
]
|
||||
}
|
||||
],
|
||||
"sourceCoverage": [
|
||||
{
|
||||
"sourceId": "sourceId sample 44",
|
||||
"coverage": "CONTEXTUAL",
|
||||
"reason": "reason sample 45"
|
||||
},
|
||||
{
|
||||
"sourceId": "sourceId sample 46",
|
||||
"coverage": "CONTEXTUAL",
|
||||
"reason": "reason sample 47"
|
||||
}
|
||||
],
|
||||
"assetPlan": [
|
||||
{
|
||||
"assetId": "assetId sample 48",
|
||||
"description": "description sample 49",
|
||||
"altText": "altText sample 50"
|
||||
},
|
||||
{
|
||||
"assetId": "assetId sample 51",
|
||||
"description": "description sample 52",
|
||||
"altText": "altText sample 53"
|
||||
}
|
||||
],
|
||||
"model": "model sample 54"
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"artifactVersion": 41,
|
||||
"schemaVersion": 42,
|
||||
"runtimeVersion": 43,
|
||||
"briefingId": "00000000-0000-4000-8000-000000000004",
|
||||
"revisionId": "00000000-0000-4000-8000-000000000005",
|
||||
"parentRevisionId": "00000000-0000-4000-8000-000000000006",
|
||||
"name": "name sample 7",
|
||||
"author": "author sample 8",
|
||||
"createdAtUtc": "2026-10-29T12:39:15+01:00",
|
||||
"targetLanguage": 1,
|
||||
"customTargetLanguage": "customTargetLanguage sample 10",
|
||||
"audienceProfile": 1,
|
||||
"audienceAgeGroup": 1,
|
||||
"audienceOrganizationalLevel": 1,
|
||||
"audienceExpertise": 1,
|
||||
"showSourceReferences": true,
|
||||
"protectionLevel": "INTERNAL",
|
||||
"customProtectionLevel": "customProtectionLevel sample 11",
|
||||
"aiStudioVersion": "aiStudioVersion sample 12",
|
||||
"runtimeAIStudioVersion": "runtimeAIStudioVersion sample 13",
|
||||
"documentHash": "documentHash sample 14"
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
{
|
||||
"manifestVersion": 41,
|
||||
"briefingId": "00000000-0000-4000-8000-000000000002",
|
||||
"name": "name sample 3",
|
||||
"author": "author sample 4",
|
||||
"createdAtUtc": "2026-10-29T12:35:15+01:00",
|
||||
"modifiedAtUtc": "2026-10-29T12:36:15+01:00",
|
||||
"settings": {
|
||||
"providerId": "providerId sample 7",
|
||||
"modelId": "modelId sample 8",
|
||||
"profileId": "profileId sample 9",
|
||||
"targetLanguage": "EN_US",
|
||||
"customTargetLanguage": "customTargetLanguage sample 10",
|
||||
"audienceProfile": "STUDENTS",
|
||||
"audienceAgeGroup": "CHILDREN",
|
||||
"audienceOrganizationalLevel": "TRAINEES",
|
||||
"audienceExpertise": "NON_EXPERTS",
|
||||
"showSourceReferences": true,
|
||||
"optimizeImages": true,
|
||||
"instruction": "instruction sample 11",
|
||||
"protectionLevel": "INTERNAL",
|
||||
"customProtectionLevel": "customProtectionLevel sample 12"
|
||||
},
|
||||
"restrictions": {
|
||||
"providerConfidence": "UNTRUSTED",
|
||||
"dataSecurity": "ALLOW_ANY",
|
||||
"outboundData": {
|
||||
"restriction": "ONLY_LINKS_FROM_CHAT",
|
||||
"origin": "MAILBOX",
|
||||
"reference": "Reference sample 13"
|
||||
},
|
||||
"webAddressesWrittenByModels": [
|
||||
"WebAddressesWrittenByModels sample 15",
|
||||
"WebAddressesWrittenByModels sample 14"
|
||||
]
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"sourceId": "00000000-0000-4000-8000-000000000016",
|
||||
"kind": "VISUAL_ASSET",
|
||||
"path": "/samples/path-17.txt",
|
||||
"size": 4000000018,
|
||||
"lastWriteTimeUtc": "2026-10-29T12:49:15+01:00",
|
||||
"transcriptStatus": "CURRENT",
|
||||
"isMedia": true,
|
||||
"assetId": "assetId sample 20"
|
||||
},
|
||||
{
|
||||
"sourceId": "00000000-0000-4000-8000-000000000021",
|
||||
"kind": "VISUAL_ASSET",
|
||||
"path": "/samples/path-22.txt",
|
||||
"size": 4000000023,
|
||||
"lastWriteTimeUtc": "2026-10-29T12:54:15+01:00",
|
||||
"transcriptStatus": "CURRENT",
|
||||
"isMedia": true,
|
||||
"assetId": "assetId sample 25"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"schemaVersion": 66,
|
||||
"intermediateArtifactVersion": 67,
|
||||
"evidenceContractVersion": 68,
|
||||
"planContractVersion": 69,
|
||||
"contentContractVersion": 70,
|
||||
"designContractVersion": 71,
|
||||
"versionNumber": 72,
|
||||
"revisionId": "00000000-0000-4000-8000-000000000033",
|
||||
"parentRevisionId": "00000000-0000-4000-8000-000000000034",
|
||||
"createdAtUtc": "2026-10-29T13:05:15+01:00",
|
||||
"editMode": "CHANGE_DESIGN",
|
||||
"instruction": "instruction sample 36",
|
||||
"documentHash": "documentHash sample 37",
|
||||
"origin": "origin sample 38",
|
||||
"fileName": "fileName sample 39",
|
||||
"dataHash": "dataHash sample 40",
|
||||
"assetHash": "assetHash sample 41",
|
||||
"templateHash": "templateHash sample 42",
|
||||
"cssHash": "cssHash sample 43",
|
||||
"runtimeHash": "runtimeHash sample 44",
|
||||
"contentArtifactId": "00000000-0000-4000-8000-000000000045",
|
||||
"evidenceArtifactId": "00000000-0000-4000-8000-000000000046",
|
||||
"planArtifactId": "00000000-0000-4000-8000-000000000047",
|
||||
"presentationArtifactId": "00000000-0000-4000-8000-000000000048",
|
||||
"buildId": "00000000-0000-4000-8000-000000000049",
|
||||
"operationId": "00000000-0000-4000-8000-000000000050",
|
||||
"modelContributions": [
|
||||
{
|
||||
"role": "PLAN",
|
||||
"model": "Model sample 51"
|
||||
},
|
||||
{
|
||||
"role": "PLAN",
|
||||
"model": "Model sample 52"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"schemaVersion": 43,
|
||||
"intermediateArtifactVersion": 44,
|
||||
"evidenceContractVersion": 45,
|
||||
"planContractVersion": 46,
|
||||
"contentContractVersion": 47,
|
||||
"designContractVersion": 48,
|
||||
"versionNumber": 49,
|
||||
"revisionId": "00000000-0000-4000-8000-000000000060",
|
||||
"parentRevisionId": "00000000-0000-4000-8000-000000000061",
|
||||
"createdAtUtc": "2026-10-29T13:32:15+01:00",
|
||||
"editMode": "CHANGE_DESIGN",
|
||||
"instruction": "instruction sample 63",
|
||||
"documentHash": "documentHash sample 64",
|
||||
"origin": "origin sample 65",
|
||||
"fileName": "fileName sample 66",
|
||||
"dataHash": "dataHash sample 67",
|
||||
"assetHash": "assetHash sample 68",
|
||||
"templateHash": "templateHash sample 69",
|
||||
"cssHash": "cssHash sample 70",
|
||||
"runtimeHash": "runtimeHash sample 71",
|
||||
"contentArtifactId": "00000000-0000-4000-8000-000000000072",
|
||||
"evidenceArtifactId": "00000000-0000-4000-8000-000000000073",
|
||||
"planArtifactId": "00000000-0000-4000-8000-000000000074",
|
||||
"presentationArtifactId": "00000000-0000-4000-8000-000000000075",
|
||||
"buildId": "00000000-0000-4000-8000-000000000076",
|
||||
"operationId": "00000000-0000-4000-8000-000000000077",
|
||||
"modelContributions": [
|
||||
{
|
||||
"role": "PLAN",
|
||||
"model": "Model sample 78"
|
||||
},
|
||||
{
|
||||
"role": "PLAN",
|
||||
"model": "Model sample 79"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"artifactVersion": 41,
|
||||
"contractVersion": 42,
|
||||
"artifactId": "00000000-0000-4000-8000-000000000003",
|
||||
"createdAtUtc": "2026-10-29T12:34:15+01:00",
|
||||
"payloadHash": "payloadHash sample 5",
|
||||
"sections": [
|
||||
{
|
||||
"sectionId": "sectionId sample 6",
|
||||
"role": "EXECUTIVE_SUMMARY",
|
||||
"titleSlotId": "titleSlotId sample 7",
|
||||
"summarySlotId": "summarySlotId sample 8",
|
||||
"components": [
|
||||
{
|
||||
"componentId": "componentId sample 9",
|
||||
"kind": "METRIC",
|
||||
"evidenceIds": [
|
||||
"evidenceIds sample 10",
|
||||
"evidenceIds sample 11"
|
||||
],
|
||||
"slots": [
|
||||
{
|
||||
"slotId": "slotId sample 12",
|
||||
"role": "TITLE"
|
||||
},
|
||||
{
|
||||
"slotId": "slotId sample 13",
|
||||
"role": "TITLE"
|
||||
}
|
||||
],
|
||||
"assetId": "assetId sample 14",
|
||||
"timelineOrientation": "VERTICAL"
|
||||
},
|
||||
{
|
||||
"componentId": "componentId sample 15",
|
||||
"kind": "METRIC",
|
||||
"evidenceIds": [
|
||||
"evidenceIds sample 16",
|
||||
"evidenceIds sample 17"
|
||||
],
|
||||
"slots": [
|
||||
{
|
||||
"slotId": "slotId sample 18",
|
||||
"role": "TITLE"
|
||||
},
|
||||
{
|
||||
"slotId": "slotId sample 19",
|
||||
"role": "TITLE"
|
||||
}
|
||||
],
|
||||
"assetId": "assetId sample 20",
|
||||
"timelineOrientation": "VERTICAL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"sectionId": "sectionId sample 21",
|
||||
"role": "EXECUTIVE_SUMMARY",
|
||||
"titleSlotId": "titleSlotId sample 22",
|
||||
"summarySlotId": "summarySlotId sample 23",
|
||||
"components": [
|
||||
{
|
||||
"componentId": "componentId sample 24",
|
||||
"kind": "METRIC",
|
||||
"evidenceIds": [
|
||||
"evidenceIds sample 25",
|
||||
"evidenceIds sample 26"
|
||||
],
|
||||
"slots": [
|
||||
{
|
||||
"slotId": "slotId sample 27",
|
||||
"role": "TITLE"
|
||||
},
|
||||
{
|
||||
"slotId": "slotId sample 28",
|
||||
"role": "TITLE"
|
||||
}
|
||||
],
|
||||
"assetId": "assetId sample 29",
|
||||
"timelineOrientation": "VERTICAL"
|
||||
},
|
||||
{
|
||||
"componentId": "componentId sample 30",
|
||||
"kind": "METRIC",
|
||||
"evidenceIds": [
|
||||
"evidenceIds sample 31",
|
||||
"evidenceIds sample 32"
|
||||
],
|
||||
"slots": [
|
||||
{
|
||||
"slotId": "slotId sample 33",
|
||||
"role": "TITLE"
|
||||
},
|
||||
{
|
||||
"slotId": "slotId sample 34",
|
||||
"role": "TITLE"
|
||||
}
|
||||
],
|
||||
"assetId": "assetId sample 35",
|
||||
"timelineOrientation": "VERTICAL"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"structuralSignature": "structuralSignature sample 36",
|
||||
"model": "model sample 37"
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"artifactVersion": 41,
|
||||
"contractVersion": 42,
|
||||
"artifactId": "00000000-0000-4000-8000-000000000003",
|
||||
"createdAtUtc": "2026-10-29T12:34:15+01:00",
|
||||
"payloadHash": "payloadHash sample 5",
|
||||
"layout": {
|
||||
"nodeId": "nodeId sample 6",
|
||||
"kind": "STACK",
|
||||
"sectionId": "sectionId sample 7",
|
||||
"componentId": "componentId sample 8",
|
||||
"children": [],
|
||||
"columns": {
|
||||
"mobile": 49,
|
||||
"tablet": 50,
|
||||
"desktop": 51
|
||||
},
|
||||
"span": 52,
|
||||
"order": 53,
|
||||
"emphasized": true,
|
||||
"alignment": "CENTER"
|
||||
},
|
||||
"profile": "EXECUTIVE",
|
||||
"templateHtml": "templateHtml sample 14",
|
||||
"css": "css sample 15",
|
||||
"templateHash": "templateHash sample 16",
|
||||
"cssHash": "cssHash sample 17",
|
||||
"model": "model sample 18"
|
||||
}
|
||||
@@ -18,6 +18,10 @@ public sealed class JsonContractTests
|
||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.RuntimeAnswers))]
|
||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ServiceRequests))]
|
||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ServiceAnswers))]
|
||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingStored))]
|
||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingHashed))]
|
||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingAnswers))]
|
||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ModelAnswers))]
|
||||
public void TheContractsMatchThoseOfReflection(JsonTestRoot root)
|
||||
{
|
||||
var baseline = JsonReflectionBaseline.Of(root.Options);
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace AIStudio.Tests.Serialization;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Files written by an older version of AI Studio lack every property added since, and an answer of a
|
||||
/// provider, of the runtime, or of a service leaves out whatever it has nothing to say about. Reading them has
|
||||
/// provider, of the runtime, of a service, or of a model leaves out whatever it has nothing to say about. Reading them has
|
||||
/// to give those properties their defaults, as a new object has them, e.g., a sub-object of the settings
|
||||
/// instead of null. Source generation in .NET 10 breaks this for init-only properties: it sets them all while
|
||||
/// creating the object, and a property missing in the JSON gets the default of its type instead
|
||||
@@ -25,6 +25,9 @@ public sealed class JsonDefaultsTests
|
||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ProviderAnswers))]
|
||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.RuntimeAnswers))]
|
||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ServiceAnswers))]
|
||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingStored))]
|
||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.VisualBriefingAnswers))]
|
||||
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ModelAnswers))]
|
||||
public void AnEmptyObjectGetsTheDefaultsOfANewOne(JsonTestRoot root)
|
||||
{
|
||||
var baseline = JsonReflectionBaseline.Of(root.Options);
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
using AIStudio.Assistants.SWOTAnalysis;
|
||||
using AIStudio.Assistants.VisualBriefing;
|
||||
using AIStudio.Chat;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Settings.DataModel;
|
||||
@@ -42,6 +43,15 @@ public sealed class JsonGoldenFileTests
|
||||
yield return new("data-restore-plan.json", typeof(DataRestorePlan), DataBackupFormat.JSON_OPTIONS);
|
||||
yield return new("data-restore-report.json", typeof(DataRestoreReport), DataBackupFormat.JSON_OPTIONS);
|
||||
yield return new("provenance-surrounding-content.json", typeof(List<string>), SqliteProvenanceStoreClientImplementation.JSON_OPTIONS);
|
||||
|
||||
// A visual briefing, with the artifacts of its stages, a build, and the header of an exported briefing:
|
||||
yield return new("visual-briefing-manifest.json", typeof(VisualBriefingManifest), VisualBriefingJson.Persistence);
|
||||
yield return new("visual-briefing-evidence-artifact.json", typeof(VisualBriefingEvidenceArtifact), VisualBriefingJson.Persistence);
|
||||
yield return new("visual-briefing-plan-artifact.json", typeof(VisualBriefingPlanArtifact), VisualBriefingJson.Persistence);
|
||||
yield return new("visual-briefing-content-artifact.json", typeof(VisualBriefingContentArtifact), VisualBriefingJson.Persistence);
|
||||
yield return new("visual-briefing-presentation-artifact.json", typeof(VisualBriefingPresentationArtifact), VisualBriefingJson.Persistence);
|
||||
yield return new("visual-briefing-build.json", typeof(VisualBriefingBuildRecord), VisualBriefingJson.Persistence);
|
||||
yield return new("visual-briefing-export-manifest.json", typeof(VisualBriefingExportManifest), VisualBriefingJson.Canonical);
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(GoldenFiles))]
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
using AIStudio.Agents;
|
||||
using AIStudio.Agents.AssistantAudit;
|
||||
using AIStudio.Assistants.Builder;
|
||||
using AIStudio.Assistants.ERI;
|
||||
using AIStudio.Assistants.PromptOptimizer;
|
||||
using AIStudio.Assistants.SWOTAnalysis;
|
||||
using AIStudio.Tools.PowerPoint;
|
||||
|
||||
namespace AIStudio.Tests.Serialization;
|
||||
|
||||
public static partial class JsonTestRoots
|
||||
{
|
||||
/// <summary>
|
||||
/// The JSON which models write for the agents and assistants of AI Studio, apart from the Visual Briefing
|
||||
/// assistant.
|
||||
/// </summary>
|
||||
public static IEnumerable<TestCaseData> ModelAnswers()
|
||||
{
|
||||
TestHost.PrepareStaticState();
|
||||
|
||||
// The agents, which select data sources, check retrieved passages, and audit assistant plugins:
|
||||
yield return Case(new(typeof(List<SelectedDataSource>), AgentBase.JSON_SERIALIZER_OPTIONS));
|
||||
yield return Case(new(typeof(RetrievalContextValidationResult), AgentBase.JSON_SERIALIZER_OPTIONS));
|
||||
yield return Case(new(typeof(AssistantAuditResult), AgentBase.JSON_SERIALIZER_OPTIONS));
|
||||
|
||||
// The Assistant Builder, for assistant plugins and for direct chat launchers:
|
||||
yield return Case(new(typeof(LuaResponse), LuaResponse.JSON_OPTIONS));
|
||||
yield return Case(new(typeof(LauncherTextsResponse), LauncherTextsResponse.JSON_OPTIONS));
|
||||
|
||||
yield return Case(new(typeof(PromptOptimizationResult), AssistantPromptOptimizer.JSON_OPTIONS));
|
||||
yield return Case(new(typeof(SwotCategoryAnalysisResult), SwotModelAnswer.JSON_OPTIONS));
|
||||
yield return Case(new(typeof(SwotModerationResult), SwotModelAnswer.JSON_OPTIONS));
|
||||
yield return Case(new(typeof(ERIServerFileList), ERIServerFileList.JSON_OPTIONS));
|
||||
yield return Case(new(typeof(SlideDeckSpec.DeckDto), SlideDeckSpec.JSON_OPTIONS));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using System.Text.Json;
|
||||
|
||||
using AIStudio.Assistants.VisualBriefing;
|
||||
|
||||
namespace AIStudio.Tests.Serialization;
|
||||
|
||||
public static partial class JsonTestRoots
|
||||
{
|
||||
/// <summary>
|
||||
/// What the Visual Briefing assistant writes and reads again: the files of a briefing, and the canonical
|
||||
/// JSON which it parses back from an exported briefing.
|
||||
/// </summary>
|
||||
public static IEnumerable<TestCaseData> VisualBriefingStored()
|
||||
{
|
||||
TestHost.PrepareStaticState();
|
||||
var options = VisualBriefingJson.Persistence;
|
||||
|
||||
yield return Case(new(typeof(VisualBriefingManifest), options));
|
||||
yield return Case(new(typeof(VisualBriefingEvidenceArtifact), options));
|
||||
yield return Case(new(typeof(VisualBriefingPlanArtifact), options));
|
||||
yield return Case(new(typeof(VisualBriefingContentArtifact), options));
|
||||
yield return Case(new(typeof(VisualBriefingPresentationArtifact), options));
|
||||
yield return Case(new(typeof(VisualBriefingBuildRecord), options));
|
||||
|
||||
// The briefing selected last, which gets written without options of its own:
|
||||
yield return Case(new(typeof(Guid?), JsonSerializerOptions.Default), "selected briefing");
|
||||
|
||||
//
|
||||
// The canonical JSON which gets read back: the header and the data of an exported briefing, the version
|
||||
// of AI Studio inside its runtime script, and the copy of a build which the progress view shows:
|
||||
//
|
||||
var canonical = VisualBriefingJson.Canonical;
|
||||
yield return Case(new(typeof(VisualBriefingExportManifest), canonical));
|
||||
yield return Case(new(typeof(Dictionary<string, JsonElement>), canonical), "data");
|
||||
yield return Case(new(typeof(string), canonical), "version");
|
||||
yield return Case(new(typeof(VisualBriefingBuildRecord), canonical), "progress");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// What the Visual Briefing assistant writes as canonical JSON without reading it again: what goes into the
|
||||
/// hashes of a briefing, into the data of a briefing, and into the prompts of its stages.
|
||||
/// </summary>
|
||||
public static IEnumerable<TestCaseData> VisualBriefingHashed()
|
||||
{
|
||||
TestHost.PrepareStaticState();
|
||||
var options = VisualBriefingJson.Canonical;
|
||||
|
||||
// The payload hashes of the artifacts:
|
||||
yield return Case(new(typeof(List<VisualBriefingEvidenceFact>), options));
|
||||
yield return Case(new(typeof(List<VisualBriefingEvidenceMetric>), options));
|
||||
yield return Case(new(typeof(List<VisualBriefingEvidenceTable>), options));
|
||||
yield return Case(new(typeof(List<VisualBriefingSourceCoverage>), options));
|
||||
yield return Case(new(typeof(List<VisualBriefingAssetPlanItem>), options));
|
||||
yield return Case(new(typeof(List<VisualBriefingPlanSection>), options));
|
||||
yield return Case(new(typeof(List<VisualBriefingSlotValue>), options));
|
||||
yield return Case(new(typeof(List<VisualBriefingChartSpec>), options));
|
||||
yield return Case(new(typeof(List<VisualBriefingControlSpec>), options));
|
||||
yield return Case(new(typeof(List<VisualBriefingFormulaSpec>), options));
|
||||
yield return Case(new(typeof(Dictionary<string, string>), options));
|
||||
yield return Case(new(typeof(Dictionary<string, List<string>>), options));
|
||||
yield return Case(new(typeof(VisualBriefingLayoutNode), options));
|
||||
|
||||
// The data of a briefing, and the IDs the prompts list:
|
||||
yield return Case(new(typeof(JsonElement), options));
|
||||
yield return Case(new(typeof(string[]), options));
|
||||
|
||||
// The position inside a repeated element, which the data bindings write without options of their own:
|
||||
yield return Case(new(typeof(int), JsonSerializerOptions.Default), "index");
|
||||
|
||||
// The diagnostics a user copies to the clipboard:
|
||||
yield return Case(new(typeof(VisualBriefingOperationDiagnostics), VisualBriefingJson.Persistence));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The answers of the models which build a visual briefing.
|
||||
/// </summary>
|
||||
public static IEnumerable<TestCaseData> VisualBriefingAnswers()
|
||||
{
|
||||
TestHost.PrepareStaticState();
|
||||
var options = VisualBriefingJson.Canonical;
|
||||
|
||||
yield return Case(new(typeof(VisualBriefingEvidenceResponse), options));
|
||||
yield return Case(new(typeof(VisualBriefingPlanResponse), options));
|
||||
yield return Case(new(typeof(VisualBriefingContentResponse), options));
|
||||
yield return Case(new(typeof(VisualBriefingDesignResponse), options));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System.Text.Json;
|
||||
|
||||
using AIStudio.Assistants.VisualBriefing;
|
||||
|
||||
namespace AIStudio.Tests.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Checks that the Visual Briefing assistant computes the same hashes and compiles the same data as before.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A stored briefing carries the hashes of its artifacts, and an exported one the hash of its document. The
|
||||
/// assistant computes them anew from the canonical JSON of the same values and discards whatever no longer
|
||||
/// matches, so a byte written otherwise makes every stored briefing fail its check. The expected hashes were
|
||||
/// computed from the files in the folder Fixtures with the contracts of reflection, before AI Studio got
|
||||
/// contracts of its own.
|
||||
/// </remarks>
|
||||
[TestFixture]
|
||||
public sealed class VisualBriefingHashTests
|
||||
{
|
||||
private static IEnumerable<TestCaseData> StoredHashes()
|
||||
{
|
||||
yield return Case("evidence", "aed455ba77468d47c30aba31a744df35639978c3d56fe30469b298aa34918752", () =>
|
||||
{
|
||||
var evidence = Read<VisualBriefingEvidenceArtifact>("visual-briefing-evidence-artifact.json", VisualBriefingJson.Persistence);
|
||||
return VisualBriefingPayloadHash.ForEvidence(evidence.Facts, evidence.Metrics, evidence.Tables, evidence.SourceCoverage, evidence.AssetPlan);
|
||||
});
|
||||
|
||||
yield return Case("plan", "311c5e8c1202a0f473a9f615c3aa3bc8f1015f8a37859b7addfcab879fa23f0d", () =>
|
||||
{
|
||||
var plan = Read<VisualBriefingPlanArtifact>("visual-briefing-plan-artifact.json", VisualBriefingJson.Persistence);
|
||||
return VisualBriefingPayloadHash.ForPlan(plan.Sections, plan.StructuralSignature);
|
||||
});
|
||||
|
||||
yield return Case("content", "1cc333a62da8a14d76c37b7eed0a1ece71b5cb48b914cde3fed1a55bf39950c2", () =>
|
||||
{
|
||||
var content = Read<VisualBriefingContentArtifact>("visual-briefing-content-artifact.json", VisualBriefingJson.Persistence);
|
||||
return VisualBriefingPayloadHash.ForContent(content.Slots, content.Charts, content.Controls, content.Formulas, content.AccessibilityTexts,
|
||||
content.SourceReferences, content.ResetLabel, content.SourceCoverage, content.AssetPlan, content.StructuralSignature);
|
||||
});
|
||||
|
||||
yield return Case("presentation", "96fc7f856c4edfba2b823b83e5cc3b09b8939124d6c5a70d07669cf61219ac3e", () =>
|
||||
{
|
||||
var presentation = Read<VisualBriefingPresentationArtifact>("visual-briefing-presentation-artifact.json", VisualBriefingJson.Persistence);
|
||||
return VisualBriefingPayloadHash.ForPresentation(presentation.Layout, presentation.Profile, presentation.TemplateHash, presentation.CssHash);
|
||||
});
|
||||
|
||||
yield return Case("header of an export", "a838f56ba91facf5186ecb63e790ed9a9419ad73c2669fd8bfed97bd8c876f99", () =>
|
||||
{
|
||||
var header = Read<VisualBriefingExportManifest>("visual-briefing-export-manifest.json", VisualBriefingJson.Canonical);
|
||||
return VisualBriefingHashing.Compute(VisualBriefingHashing.CanonicalJson(header));
|
||||
});
|
||||
}
|
||||
|
||||
[TestCaseSource(nameof(StoredHashes))]
|
||||
public void AStoredBriefingGetsTheSameHash(Func<string> computeHash, string expectedHash) => Assert.That(computeHash(), Is.EqualTo(expectedHash));
|
||||
|
||||
[Test]
|
||||
public void TheDataOfABriefingGetsCompiledAsBefore()
|
||||
{
|
||||
var compiled = VisualBriefingLayoutCompiler.Compile(VisualBriefingSamples.Plan(), VisualBriefingSamples.Content(), VisualBriefingSamples.Layout(), VisualBriefingDesignProfile.EDITORIAL);
|
||||
Assert.That(compiled.Data.GetRawText(), Is.EqualTo(JsonGoldenFileTests.ReadFixture("visual-briefing-compiled-data.json")));
|
||||
}
|
||||
|
||||
private static TestCaseData Case(string name, string expectedHash, Func<string> computeHash) => new TestCaseData(computeHash, expectedHash).SetArgDisplayNames(name);
|
||||
|
||||
private static T Read<T>(string fileName, JsonSerializerOptions options) => JsonSerializer.Deserialize<T>(JsonGoldenFileTests.ReadFixture(fileName), options)!;
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
using System.Text.Json;
|
||||
|
||||
using AIStudio.Assistants.VisualBriefing;
|
||||
|
||||
namespace AIStudio.Tests.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// A made-up visual briefing for the tests which check the JSON the Visual Briefing assistant compiles.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The briefing holds one chart of every kind and a simulation with controls and a formula, so that every shape
|
||||
/// of the compiled data occurs. Its layout holds no components: the data of a briefing comes from its content
|
||||
/// alone.
|
||||
/// </remarks>
|
||||
internal static class VisualBriefingSamples
|
||||
{
|
||||
private static readonly VisualBriefingChartKind[] CHART_KINDS = Enum.GetValues<VisualBriefingChartKind>();
|
||||
|
||||
internal static VisualBriefingPlanArtifact Plan() => new()
|
||||
{
|
||||
Sections =
|
||||
[
|
||||
new()
|
||||
{
|
||||
SectionId = "overview",
|
||||
Role = VisualBriefingSectionRole.HERO,
|
||||
TitleSlotId = "overview-title",
|
||||
SummarySlotId = "overview-summary",
|
||||
Components =
|
||||
[
|
||||
.. CHART_KINDS.Select(kind => new VisualBriefingPlanComponent
|
||||
{
|
||||
ComponentId = ChartId(kind),
|
||||
Kind = VisualBriefingComponentKind.CHART,
|
||||
EvidenceIds = ["F1"],
|
||||
Slots =
|
||||
[
|
||||
new() { SlotId = $"{ChartId(kind)}-title", Role = VisualBriefingSlotRole.TITLE },
|
||||
new() { SlotId = $"{ChartId(kind)}-caption", Role = VisualBriefingSlotRole.CAPTION },
|
||||
],
|
||||
}),
|
||||
|
||||
new()
|
||||
{
|
||||
ComponentId = "simulation",
|
||||
Kind = VisualBriefingComponentKind.SIMULATION,
|
||||
EvidenceIds = ["M1"],
|
||||
Slots =
|
||||
[
|
||||
new() { SlotId = "simulation-title", Role = VisualBriefingSlotRole.TITLE },
|
||||
new() { SlotId = "simulation-summary", Role = VisualBriefingSlotRole.SUMMARY },
|
||||
new() { SlotId = "simulation-result", Role = VisualBriefingSlotRole.RESULT },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
internal static VisualBriefingContentArtifact Content()
|
||||
{
|
||||
var plan = Plan();
|
||||
var slotIds = plan.Sections.SelectMany(section => new[] { section.TitleSlotId, section.SummarySlotId }
|
||||
.Concat(section.Components.SelectMany(component => component.Slots.Select(slot => slot.SlotId))));
|
||||
|
||||
return new()
|
||||
{
|
||||
Slots = [.. slotIds.Select(slotId => new VisualBriefingSlotValue { SlotId = slotId, Value = Json($"\"Text of {slotId}, with Größe and €\"") })],
|
||||
Charts =
|
||||
[
|
||||
.. CHART_KINDS.Select(kind => new VisualBriefingChartSpec
|
||||
{
|
||||
ComponentId = ChartId(kind),
|
||||
Kind = kind,
|
||||
Categories = ["Q1", "Q2", "Q3"],
|
||||
Series =
|
||||
[
|
||||
new() { Name = "Revenue", Values = [12.5m, 14m, 9.75m] },
|
||||
new() { Name = "Costs", Values = [8m, 7.25m, 10m] },
|
||||
],
|
||||
}),
|
||||
],
|
||||
|
||||
Controls =
|
||||
[
|
||||
new()
|
||||
{
|
||||
ControlId = "growth",
|
||||
ComponentId = "simulation",
|
||||
Kind = VisualBriefingControlKind.RANGE,
|
||||
InitialValue = Json("3"),
|
||||
},
|
||||
|
||||
new()
|
||||
{
|
||||
ControlId = "scenario",
|
||||
ComponentId = "simulation",
|
||||
Kind = VisualBriefingControlKind.SELECT,
|
||||
InitialValue = Json("\"base\""),
|
||||
Options =
|
||||
[
|
||||
new() { Value = "base", Label = "Base case" },
|
||||
new() { Value = "high", Label = "Größeres Wachstum" },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
Formulas =
|
||||
[
|
||||
new()
|
||||
{
|
||||
ComponentId = "simulation",
|
||||
OutputSlotId = "simulation-result",
|
||||
Formula = new()
|
||||
{
|
||||
FormulaVersion = 1,
|
||||
Operation = "multiply",
|
||||
Arguments =
|
||||
[
|
||||
new() { Path = "interactions.state.growth" },
|
||||
new() { Value = Json("2") },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
AccessibilityTexts = new(StringComparer.Ordinal)
|
||||
{
|
||||
[ChartId(VisualBriefingChartKind.LINE)] = "Revenue rises in Q2 and falls in Q3.",
|
||||
["simulation"] = "The growth changes the result.",
|
||||
},
|
||||
|
||||
SourceReferences = new(StringComparer.Ordinal)
|
||||
{
|
||||
[ChartId(VisualBriefingChartKind.LINE)] = ["S1", "S2"],
|
||||
},
|
||||
|
||||
ResetLabel = "Zurücksetzen",
|
||||
};
|
||||
}
|
||||
|
||||
internal static VisualBriefingLayoutNode Layout() => new()
|
||||
{
|
||||
NodeId = "root",
|
||||
Kind = VisualBriefingLayoutNodeKind.STACK,
|
||||
};
|
||||
|
||||
private static string ChartId(VisualBriefingChartKind kind) => $"chart-{kind.ToString().ToLowerInvariant()}";
|
||||
|
||||
private static JsonElement Json(string json)
|
||||
{
|
||||
using var document = JsonDocument.Parse(json);
|
||||
return document.RootElement.Clone();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user