Generated the JSON contracts of visual briefings and model answers at compile time (#1151)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-11-03 14:20:41 +01:00
1 parent 24e3c22db3
commit 770c16e20a
101 files changed
+2333 -392

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,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 @@
{"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":[{"componentId":"chart-line","kind":"LINE","categories":["Q1","Q2","Q3"],"series":[{"name":"Revenue","values":[12.5,14,9.75]},{"name":"Costs","values":[8,7.25,10]}]},{"componentId":"chart-area","kind":"AREA","categories":["Q1","Q2","Q3"],"series":[{"name":"Revenue","values":[12.5,14,9.75]},{"name":"Costs","values":[8,7.25,10]}]},{"componentId":"chart-bar","kind":"BAR","categories":["Q1","Q2","Q3"],"series":[{"name":"Revenue","values":[12.5,14,9.75]},{"name":"Costs","values":[8,7.25,10]}]},{"componentId":"chart-stacked_bar","kind":"STACKED_BAR","categories":["Q1","Q2","Q3"],"series":[{"name":"Revenue","values":[12.5,14,9.75]},{"name":"Costs","values":[8,7.25,10]}]},{"componentId":"chart-scatter","kind":"SCATTER","categories":["Q1","Q2","Q3"],"series":[{"name":"Revenue","values":[12.5,14,9.75]},{"name":"Costs","values":[8,7.25,10]}]},{"componentId":"chart-pie","kind":"PIE","categories":["Q1","Q2","Q3"],"series":[{"name":"Revenue","values":[12.5,14,9.75]},{"name":"Costs","values":[8,7.25,10]}]},{"componentId":"chart-donut","kind":"DONUT","categories":["Q1","Q2","Q3"],"series":[{"name":"Revenue","values":[12.5,14,9.75]},{"name":"Costs","values":[8,7.25,10]}]},{"componentId":"chart-radar","kind":"RADAR","categories":["Q1","Q2","Q3"],"series":[{"name":"Revenue","values":[12.5,14,9.75]},{"name":"Costs","values":[8,7.25,10]}]}],"controls":[{"controlId":"growth","componentId":"simulation","kind":"RANGE","initialValue":3,"options":[]},{"controlId":"scenario","componentId":"simulation","kind":"SELECT","initialValue":"base","options":[{"value":"base","label":"Base case"},{"value":"high","label":"Gr\u00F6\u00DFeres Wachstum"}]}],"formulas":[{"componentId":"simulation","outputSlotId":"simulation-result","formula":{"formulaVersion":1,"op":"multiply","args":[{"path":"interactions.state.growth"},{"value":2}]}}],"accessibility":{"chart-line":"Revenue rises in Q2 and falls in Q3.","simulation":"The growth changes the result."},"sourceReferences":{"chart-line":["S1","S2"]},"labels":{"reset":"Zur\u00FCcksetzen","brand":"MindWork AI Studio"}}
@@ -0,0 +1,10 @@
Target language: Use the language English (US) (EN_US) for your output.
Audience: STUDENTS; CHILDREN; TRAINEES; NON_EXPERTS
Scope instruction: instruction sample 11
Exact planned component IDs: ["chart-line","chart-area","chart-bar","chart-stacked_bar","chart-scatter","chart-pie","chart-donut","chart-radar","simulation"]
Exact keys of accessibilityTexts, no others: ["chart-line","chart-area","chart-bar","chart-stacked_bar","chart-scatter","chart-pie","chart-donut","chart-radar","simulation"]
Exact required slot IDs with their semantic role and declared type, each to be returned exactly once: [{"slotId":"overview-title","role":"TITLE","type":"TEXT"},{"slotId":"overview-summary","role":"SUMMARY","type":"TEXT"},{"slotId":"chart-line-title","role":"TITLE","type":"TEXT"},{"slotId":"chart-line-caption","role":"CAPTION","type":"TEXT"},{"slotId":"chart-area-title","role":"TITLE","type":"TEXT"},{"slotId":"chart-area-caption","role":"CAPTION","type":"TEXT"},{"slotId":"chart-bar-title","role":"TITLE","type":"TEXT"},{"slotId":"chart-bar-caption","role":"CAPTION","type":"TEXT"},{"slotId":"chart-stacked_bar-title","role":"TITLE","type":"TEXT"},{"slotId":"chart-stacked_bar-caption","role":"CAPTION","type":"TEXT"},{"slotId":"chart-scatter-title","role":"TITLE","type":"TEXT"},{"slotId":"chart-scatter-caption","role":"CAPTION","type":"TEXT"},{"slotId":"chart-pie-title","role":"TITLE","type":"TEXT"},{"slotId":"chart-pie-caption","role":"CAPTION","type":"TEXT"},{"slotId":"chart-donut-title","role":"TITLE","type":"TEXT"},{"slotId":"chart-donut-caption","role":"CAPTION","type":"TEXT"},{"slotId":"chart-radar-title","role":"TITLE","type":"TEXT"},{"slotId":"chart-radar-caption","role":"CAPTION","type":"TEXT"},{"slotId":"simulation-title","role":"TITLE","type":"TEXT"},{"slotId":"simulation-summary","role":"SUMMARY","type":"TEXT"},{"slotId":"simulation-result","role":"RESULT","type":"TEXT"}]
Exact chart component IDs, each to receive exactly one chart: ["chart-line","chart-area","chart-bar","chart-stacked_bar","chart-scatter","chart-pie","chart-donut","chart-radar"]
Exact control and formula requirements, no controls for any other component: [{"componentId":"simulation","kind":"SIMULATION","panelSlotIds":[],"resultSlotIds":["simulation-result"]}]
Plan: [{"sectionId":"overview","role":"HERO","titleSlotId":"overview-title","summarySlotId":"overview-summary","components":[{"componentId":"chart-line","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-line-title","role":"TITLE"},{"slotId":"chart-line-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-area","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-area-title","role":"TITLE"},{"slotId":"chart-area-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-bar","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-bar-title","role":"TITLE"},{"slotId":"chart-bar-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-stacked_bar","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-stacked_bar-title","role":"TITLE"},{"slotId":"chart-stacked_bar-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-scatter","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-scatter-title","role":"TITLE"},{"slotId":"chart-scatter-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-pie","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-pie-title","role":"TITLE"},{"slotId":"chart-pie-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-donut","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-donut-title","role":"TITLE"},{"slotId":"chart-donut-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-radar","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-radar-title","role":"TITLE"},{"slotId":"chart-radar-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"simulation","kind":"SIMULATION","evidenceIds":["M1"],"slots":[{"slotId":"simulation-title","role":"TITLE"},{"slotId":"simulation-summary","role":"SUMMARY"},{"slotId":"simulation-result","role":"RESULT"}],"assetId":null,"timelineOrientation":null}]}]
Evidence: {"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"]}],"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"}]}
@@ -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,4 @@
Target language: Use the language English (US) (EN_US) for your output.
Scope instruction: instruction sample 11
Sources, in the same order as the attached files: [{"sourceId":"s1","kind":"VISUAL_ASSET","assetId":"assetId sample 20","name":"path-17.txt"},{"sourceId":"s2","kind":"VISUAL_ASSET","assetId":"assetId sample 25","name":"path-22.txt"}]
Media transcripts: {"s1":"The transcript of a recording, with Gr\u00F6\u00DFe and \u20AC."}
@@ -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 @@
{"name":"name sample 3","author":"author sample 4","settings":{"providerId":"providerId sample 7","modelId":"modelId sample 8","profileId":"profileId sample 9","targetLanguage":1,"customTargetLanguage":"customTargetLanguage sample 10","audienceProfile":1,"audienceAgeGroup":1,"audienceOrganizationalLevel":1,"audienceExpertise":1,"showSourceReferences":true,"optimizeImages":true,"instruction":"instruction sample 11","protectionLevel":"INTERNAL","customProtectionLevel":"customProtectionLevel sample 12"},"sources":[{"path":"/samples/path-17.txt","kind":"VISUAL_ASSET"},{"path":"/samples/path-22.txt","kind":"VISUAL_ASSET"}]}
@@ -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,3 @@
Audience: STUDENTS; CHILDREN; TRAINEES; NON_EXPERTS
Scope instruction: instruction sample 11
Evidence: {"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"]}],"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"}]}
@@ -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"
}
@@ -0,0 +1,6 @@
Operation: CHANGE_DESIGN
Design instruction: instruction sample 11
Planned sections and components:
[{"sectionId":"overview","role":"HERO","titleSlotId":"overview-title","summarySlotId":"overview-summary","components":[{"componentId":"chart-line","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-line-title","role":"TITLE"},{"slotId":"chart-line-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-area","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-area-title","role":"TITLE"},{"slotId":"chart-area-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-bar","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-bar-title","role":"TITLE"},{"slotId":"chart-bar-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-stacked_bar","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-stacked_bar-title","role":"TITLE"},{"slotId":"chart-stacked_bar-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-scatter","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-scatter-title","role":"TITLE"},{"slotId":"chart-scatter-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-pie","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-pie-title","role":"TITLE"},{"slotId":"chart-pie-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-donut","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-donut-title","role":"TITLE"},{"slotId":"chart-donut-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"chart-radar","kind":"CHART","evidenceIds":["F1"],"slots":[{"slotId":"chart-radar-title","role":"TITLE"},{"slotId":"chart-radar-caption","role":"CAPTION"}],"assetId":null,"timelineOrientation":null},{"componentId":"simulation","kind":"SIMULATION","evidenceIds":["M1"],"slots":[{"slotId":"simulation-title","role":"TITLE"},{"slotId":"simulation-summary","role":"SUMMARY"},{"slotId":"simulation-result","role":"RESULT"}],"assetId":null,"timelineOrientation":null}]}]
Parent design:
{"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"}
@@ -0,0 +1 @@
{"slots":{"title":"Gr\u00F6\u00DFe"},"_mwai":{"schemaVersion":2,"runtimeVersion":1,"aiStudioVersion":"__VERSION__","assets":{"asset-1":"data:image/png;base64,AA=="},"assetMetadata":{"asset-1":{"description":"A chart of the quarter","altText":"Revenue per quarter, with Gr\u00F6\u00DFe"}},"footer":{"createdWith":"Created with MindWork AI Studio v__VERSION__.","models":"Contributing models: Model A (content); Model B (presentation).","createdAt":"Revision created on 2026-11-03.","authors":"Author(s): author sample 4.","protection":"Protection level: internal."}}}
@@ -0,0 +1 @@
{"schemaVersion":2,"runtimeVersion":1,"aiStudioVersion":"validation","assets":{"assetId sample 48":"data:image/png;base64,AA==","assetId sample 51":"data:image/png;base64,AA=="},"footer":{"createdWith":"validation","models":"validation","createdAt":"validation","authors":"validation","protection":"validation"}}
@@ -18,6 +18,11 @@ 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))]
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ModelPrompts))]
public void TheContractsMatchThoseOfReflection(JsonTestRoot root)
{
var baseline = JsonReflectionBaseline.Of(root.Options);
@@ -20,6 +20,11 @@ public sealed class JsonCoverageTests
[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))]
[TestCaseSource(typeof(JsonTestRoots), nameof(JsonTestRoots.ModelPrompts))]
public void EveryContractComesFromSourceGeneration(JsonTestRoot root)
{
var typesWithoutGeneratedContract = JsonTypeGraph.Collect(root.Type, root.Options)
+4 -1
View File
@@ -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,53 @@
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;
using AIStudio.Tools.Services;
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));
}
/// <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));
}
}
@@ -0,0 +1,104 @@
using System.Text.Json;
using System.Text.Json.Nodes;
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:
yield return Case(new(typeof(Guid?), options), "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, with what the compilers and the stages put into it:
yield return Case(new(typeof(JsonElement), options));
yield return Case(new(typeof(JsonObject), options));
yield return Case(new(typeof(VisualBriefingCompiledData), options));
yield return Case(new(typeof(VisualBriefingContentData), options));
yield return Case(new(typeof(VisualBriefingInteractionData), options));
yield return Case(new(typeof(VisualBriefingProtectedData), options));
yield return Case(new(typeof(string), options), "value of a control");
// The position inside a repeated element, which the data bindings write:
yield return Case(new(typeof(int), options), "index");
// What the prompts of the stages carry:
yield return Case(new(typeof(IEnumerable<VisualBriefingSourcePrompt>), options));
yield return Case(new(typeof(string[]), options));
yield return Case(new(typeof(VisualBriefingRequiredSlot[]), options));
yield return Case(new(typeof(VisualBriefingControlRequirement[]), options));
yield return Case(new(typeof(VisualBriefingEvidencePrompt), options));
yield return Case(new(typeof(VisualBriefingParentDesign), options));
// The fingerprint which decides whether the editor holds unsaved changes:
yield return Case(new(typeof(VisualBriefingPersistenceFingerprint), options));
// 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,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");
}
@@ -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,60 @@
using System.Reflection;
using System.Text.Json;
using AIStudio.Assistants.VisualBriefing;
using AIStudio.Tools.Metadata;
namespace AIStudio.Tests.Serialization;
/// <summary>
/// Checks that the stages of the Visual Briefing assistant send their models the same JSON as before, and that an
/// exported briefing gets the same protected data.
/// </summary>
/// <remarks>
/// The files in the folder Fixtures were written with the contracts of reflection, before AI Studio got
/// contracts of its own. 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 builds. The protected data of an exported briefing is checked when the briefing
/// gets imported again. The fixture of the protected data names the version of AI Studio as a placeholder,
/// because every release changes it.
/// </remarks>
[TestFixture]
public sealed class VisualBriefingPromptTests
{
private const string VERSION_PLACEHOLDER = "__VERSION__";
private static IEnumerable<TestCaseData> Prompts()
{
yield return Case("visual-briefing-evidence-prompt.txt", () =>
{
var manifest = Manifest();
return VisualBriefingEvidenceStage.BuildPrompt(manifest, VisualBriefingSamples.PreparedSources(manifest));
});
yield return Case("visual-briefing-plan-prompt.txt", () => VisualBriefingPlanStage.BuildPrompt(Manifest(), Evidence()));
yield return Case("visual-briefing-content-prompt.txt", () => VisualBriefingContentStage.BuildPrompt(Manifest(), Evidence(), VisualBriefingSamples.Plan()));
yield return Case("visual-briefing-presentation-prompt.txt", () => VisualBriefingPresentationStage.BuildPrompt(Manifest(), VisualBriefingSamples.Plan(), Presentation()));
}
[TestCaseSource(nameof(Prompts))]
public void APromptCarriesTheSameJsonAsBefore(string fileName, Func<string> buildPrompt) => Assert.That(buildPrompt(), Is.EqualTo(JsonGoldenFileTests.ReadFixture(fileName)));
[Test]
public void AnExportedBriefingGetsTheSameProtectedData()
{
var manifest = Manifest();
var data = VisualBriefingArtifactService.AddProtectedArtifactData(manifest, VisualBriefingSamples.RevisionRequest(manifest));
var version = typeof(VisualBriefingArtifactService).Assembly.GetCustomAttribute<MetaDataAttribute>()?.Version ?? "unknown";
Assert.That(data.GetRawText(), Is.EqualTo(JsonGoldenFileTests.ReadFixture("visual-briefing-protected-data.json").Replace(VERSION_PLACEHOLDER, version, StringComparison.Ordinal)));
}
private static TestCaseData Case(string fileName, Func<string> buildPrompt) => new TestCaseData(fileName, buildPrompt).SetArgDisplayNames(fileName);
private static VisualBriefingManifest Manifest() => Read<VisualBriefingManifest>("visual-briefing-manifest.json");
private static VisualBriefingEvidenceArtifact Evidence() => Read<VisualBriefingEvidenceArtifact>("visual-briefing-evidence-artifact.json");
private static VisualBriefingPresentationArtifact Presentation() => Read<VisualBriefingPresentationArtifact>("visual-briefing-presentation-artifact.json");
private static T Read<T>(string fileName) => JsonSerializer.Deserialize<T>(JsonGoldenFileTests.ReadFixture(fileName), VisualBriefingJson.Persistence)!;
}
@@ -0,0 +1,194 @@
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,
};
/// <summary>
/// The prepared sources of a briefing, with a transcript for its first source.
/// </summary>
internal static VisualBriefingPreparedSources PreparedSources(VisualBriefingManifest manifest) => new()
{
Transcripts = new Dictionary<Guid, string>
{
[manifest.Sources[0].SourceId] = "The transcript of a recording, with Größe and €.",
},
};
/// <summary>
/// A new revision of a briefing, with an embedded picture and two models which contributed to it.
/// </summary>
internal static VisualBriefingRevisionRequest RevisionRequest(VisualBriefingManifest manifest) => new(
BriefingId: manifest.BriefingId,
ParentRevisionId: null,
EditMode: VisualBriefingEditMode.INITIAL,
Instruction: "Summarize the quarter.",
Data: Json("""{"slots":{"title":"Größe"},"assets":{"old":"x"},"footerTemplates":{},"protectionLabel":"x","_mwai":{}}"""),
TemplateHtml: "<main></main>",
Css: "main {}",
ModelDisplayName: "Model A",
Origin: "test",
ModelContributions:
[
new(VisualBriefingModelRole.CONTENT, "Model A"),
new(VisualBriefingModelRole.DESIGN, "Model B"),
],
CreatedAtUtc: new DateTimeOffset(2026, 11, 3, 9, 30, 0, TimeSpan.Zero),
EmbeddedAssets: new Dictionary<string, string>(StringComparer.Ordinal)
{
["asset-1"] = "data:image/png;base64,AA==",
},
AssetPlan:
[
new() { AssetId = "asset-1", Description = "A chart of the quarter", AltText = "Revenue per quarter, with Größe" },
]);
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();
}
}
@@ -0,0 +1,47 @@
using System.Text.Json;
using AIStudio.Assistants.VisualBriefing;
namespace AIStudio.Tests.Serialization;
/// <summary>
/// Checks that the records of the Visual Briefing assistant write the same JSON as the anonymous shapes they replaced.
/// </summary>
/// <remarks>
/// The files in the folder Fixtures were written by the anonymous shapes themselves, before the records existed. The
/// content data and the protected data for the validation reach the HTML of a briefing, and the fingerprint of the
/// editor decides whether a briefing gets saved: a field under another name or in another place changes all three.
/// </remarks>
[TestFixture]
public sealed class VisualBriefingShapeTests
{
[Test]
public void TheContentDataGetsWrittenAsBefore()
{
var data = JsonSerializer.SerializeToElement(VisualBriefingContentData.Of(VisualBriefingSamples.Content()), VisualBriefingJson.Canonical);
Assert.That(data.GetRawText(), Is.EqualTo(JsonGoldenFileTests.ReadFixture("visual-briefing-content-data.json")));
}
[Test]
public void TheProtectedDataForTheValidationGetsWrittenAsBefore()
{
var evidence = Read<VisualBriefingEvidenceArtifact>("visual-briefing-evidence-artifact.json");
var data = JsonSerializer.SerializeToElement(VisualBriefingProtectedData.ForValidation(evidence.AssetPlan), VisualBriefingJson.Canonical);
Assert.That(data.GetRawText(), Is.EqualTo(JsonGoldenFileTests.ReadFixture("visual-briefing-validation-protected-data.json")));
}
[Test]
public void TheFingerprintOfTheEditorGetsWrittenAsBefore()
{
var manifest = Read<VisualBriefingManifest>("visual-briefing-manifest.json");
var fingerprint = new VisualBriefingPersistenceFingerprint(
manifest.Name,
manifest.Author,
manifest.Settings,
[.. manifest.Sources.Select(source => new VisualBriefingSourceFingerprint(source.Path, source.Kind))]);
Assert.That(JsonSerializer.Serialize(fingerprint, VisualBriefingJson.Canonical), Is.EqualTo(JsonGoldenFileTests.ReadFixture("visual-briefing-persistence-fingerprint.json")));
}
private static T Read<T>(string fileName) => JsonSerializer.Deserialize<T>(JsonGoldenFileTests.ReadFixture(fileName), VisualBriefingJson.Persistence)!;
}