mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-08-11 19:52:10 +00:00
Renamed VisualBriefingJson options
This commit is contained in:
parent
c2d3b410f2
commit
ebb9a6f135
@ -30,9 +30,9 @@ public sealed partial class VisualBriefingArtifactService
|
|||||||
private const string DATA_ELEMENT_ID = "mwai-briefing-data";
|
private const string DATA_ELEMENT_ID = "mwai-briefing-data";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the shared compact JSON configuration.
|
/// Gets the frozen JSON configuration whose bytes the document hash covers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static readonly JsonSerializerOptions JSON_OPTIONS = VisualBriefingJson.Compact;
|
private static readonly JsonSerializerOptions JSON_OPTIONS = VisualBriefingJson.Canonical;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines <c>HtmlLanguageTagRegex</c> for the visual briefing feature.
|
/// Defines <c>HtmlLanguageTagRegex</c> for the visual briefing feature.
|
||||||
|
|||||||
@ -380,5 +380,5 @@ public partial class VisualBriefingAssistant
|
|||||||
this.editor.Author,
|
this.editor.Author,
|
||||||
Settings = this.editor.ToSettings(),
|
Settings = this.editor.ToSettings(),
|
||||||
Sources = this.editor.ToSources().Select(source => new { source.Path, source.Kind }).ToArray(),
|
Sources = this.editor.ToSources().Select(source => new { source.Path, source.Kind }).ToArray(),
|
||||||
}, VisualBriefingJson.Compact);
|
}, VisualBriefingJson.Canonical);
|
||||||
}
|
}
|
||||||
@ -135,12 +135,12 @@ internal sealed partial class VisualBriefingBuildOrchestrator
|
|||||||
authors = "validation",
|
authors = "validation",
|
||||||
protection = "validation",
|
protection = "validation",
|
||||||
},
|
},
|
||||||
}, VisualBriefingJson.Compact);
|
}, VisualBriefingJson.Canonical);
|
||||||
|
|
||||||
VisualBriefingCompilerInvariant.Guard(
|
VisualBriefingCompilerInvariant.Guard(
|
||||||
VisualBriefingBuildStage.COMPILATION,
|
VisualBriefingBuildStage.COMPILATION,
|
||||||
VisualBriefingArtifactService.ValidateGeneratedParts(manifest,
|
VisualBriefingArtifactService.ValidateGeneratedParts(manifest,
|
||||||
JsonSerializer.SerializeToElement(validationDataProperties, VisualBriefingJson.Compact),
|
JsonSerializer.SerializeToElement(validationDataProperties, VisualBriefingJson.Canonical),
|
||||||
compiled.TemplateHtml, compiled.Css,
|
compiled.TemplateHtml, compiled.Css,
|
||||||
content.Charts.Count > 0));
|
content.Charts.Count > 0));
|
||||||
|
|
||||||
@ -151,7 +151,7 @@ internal sealed partial class VisualBriefingBuildOrchestrator
|
|||||||
ArtifactId = Guid.NewGuid(),
|
ArtifactId = Guid.NewGuid(),
|
||||||
CreatedAtUtc = DateTimeOffset.UtcNow,
|
CreatedAtUtc = DateTimeOffset.UtcNow,
|
||||||
PayloadHash = VisualBriefingHashing.ComputeSections(
|
PayloadHash = VisualBriefingHashing.ComputeSections(
|
||||||
JsonSerializer.Serialize(previousPresentation.Layout, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(previousPresentation.Layout, VisualBriefingJson.Canonical),
|
||||||
previousPresentation.Profile.ToString(),
|
previousPresentation.Profile.ToString(),
|
||||||
compiled.TemplateHash,
|
compiled.TemplateHash,
|
||||||
compiled.CssHash),
|
compiled.CssHash),
|
||||||
|
|||||||
@ -21,8 +21,8 @@ public sealed class VisualBriefingBuildProgressService
|
|||||||
public void Publish(VisualBriefingBuildRecord build)
|
public void Publish(VisualBriefingBuildRecord build)
|
||||||
{
|
{
|
||||||
var snapshot = JsonSerializer.Deserialize<VisualBriefingBuildRecord>(
|
var snapshot = JsonSerializer.Deserialize<VisualBriefingBuildRecord>(
|
||||||
JsonSerializer.Serialize(build, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(build, VisualBriefingJson.Canonical),
|
||||||
VisualBriefingJson.Compact)!;
|
VisualBriefingJson.Canonical)!;
|
||||||
snapshot.Instruction = string.Empty;
|
snapshot.Instruction = string.Empty;
|
||||||
this.latest[build.BriefingId] = snapshot;
|
this.latest[build.BriefingId] = snapshot;
|
||||||
this.Changed?.Invoke(build.BriefingId);
|
this.Changed?.Invoke(build.BriefingId);
|
||||||
|
|||||||
@ -125,7 +125,7 @@ internal static class VisualBriefingChartCompiler
|
|||||||
: series,
|
: series,
|
||||||
};
|
};
|
||||||
|
|
||||||
return JsonSerializer.SerializeToElement(option, VisualBriefingJson.Compact);
|
return JsonSerializer.SerializeToElement(option, VisualBriefingJson.Canonical);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -65,19 +65,19 @@ internal sealed class VisualBriefingContentStage(StructuredLlmStageRunner stageR
|
|||||||
reset = artifact.ResetLabel,
|
reset = artifact.ResetLabel,
|
||||||
brand = "MindWork AI Studio",
|
brand = "MindWork AI Studio",
|
||||||
},
|
},
|
||||||
}, VisualBriefingJson.Compact);
|
}, VisualBriefingJson.Canonical);
|
||||||
|
|
||||||
// Keep in sync with the verification in VisualBriefingStore.ReadContentArtifactAsync:
|
// Keep in sync with the verification in VisualBriefingStore.ReadContentArtifactAsync:
|
||||||
artifact.PayloadHash = VisualBriefingHashing.ComputeSections(
|
artifact.PayloadHash = VisualBriefingHashing.ComputeSections(
|
||||||
JsonSerializer.Serialize(artifact.Slots, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.Slots, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.Charts, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.Charts, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.Controls, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.Controls, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.Formulas, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.Formulas, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.AccessibilityTexts, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.AccessibilityTexts, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.SourceReferences, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.SourceReferences, VisualBriefingJson.Canonical),
|
||||||
artifact.ResetLabel,
|
artifact.ResetLabel,
|
||||||
JsonSerializer.Serialize(artifact.SourceCoverage, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.SourceCoverage, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.AssetPlan, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.AssetPlan, VisualBriefingJson.Canonical),
|
||||||
artifact.StructuralSignature);
|
artifact.StructuralSignature);
|
||||||
|
|
||||||
await store.WriteContentArtifactAsync(manifest.BriefingId, artifact, token);
|
await store.WriteContentArtifactAsync(manifest.BriefingId, artifact, token);
|
||||||
@ -170,13 +170,13 @@ internal sealed class VisualBriefingContentStage(StructuredLlmStageRunner stageR
|
|||||||
Target language: {manifest.Settings.TargetLanguage.PromptGeneralPurpose(manifest.Settings.CustomTargetLanguage)}
|
Target language: {manifest.Settings.TargetLanguage.PromptGeneralPurpose(manifest.Settings.CustomTargetLanguage)}
|
||||||
Audience: {manifest.Settings.AudienceProfile}; {manifest.Settings.AudienceAgeGroup}; {manifest.Settings.AudienceOrganizationalLevel}; {manifest.Settings.AudienceExpertise}
|
Audience: {manifest.Settings.AudienceProfile}; {manifest.Settings.AudienceAgeGroup}; {manifest.Settings.AudienceOrganizationalLevel}; {manifest.Settings.AudienceExpertise}
|
||||||
Scope instruction: {manifest.Settings.Instruction}
|
Scope instruction: {manifest.Settings.Instruction}
|
||||||
Exact planned component IDs: {JsonSerializer.Serialize(componentIds, VisualBriefingJson.Compact)}
|
Exact planned component IDs: {JsonSerializer.Serialize(componentIds, VisualBriefingJson.Canonical)}
|
||||||
Exact keys of accessibilityTexts, no others: {JsonSerializer.Serialize(accessibilityTextKeys, VisualBriefingJson.Compact)}
|
Exact keys of accessibilityTexts, no others: {JsonSerializer.Serialize(accessibilityTextKeys, VisualBriefingJson.Canonical)}
|
||||||
Exact required slot IDs with their semantic role and declared type, each to be returned exactly once: {JsonSerializer.Serialize(requiredSlots, VisualBriefingJson.Compact)}
|
Exact required slot IDs with their semantic role and declared type, each to be returned exactly once: {JsonSerializer.Serialize(requiredSlots, VisualBriefingJson.Canonical)}
|
||||||
Exact chart component IDs, each to receive exactly one chart: {JsonSerializer.Serialize(chartComponentIds, VisualBriefingJson.Compact)}
|
Exact chart component IDs, each to receive exactly one chart: {JsonSerializer.Serialize(chartComponentIds, VisualBriefingJson.Canonical)}
|
||||||
Exact control and formula requirements, no controls for any other component: {JsonSerializer.Serialize(controlRequirements, VisualBriefingJson.Compact)}
|
Exact control and formula requirements, no controls for any other component: {JsonSerializer.Serialize(controlRequirements, VisualBriefingJson.Canonical)}
|
||||||
Plan: {JsonSerializer.Serialize(plan.Sections, VisualBriefingJson.Compact)}
|
Plan: {JsonSerializer.Serialize(plan.Sections, VisualBriefingJson.Canonical)}
|
||||||
Evidence: {JsonSerializer.Serialize(new { evidence.Facts, evidence.Metrics, evidence.Tables, evidence.AssetPlan }, VisualBriefingJson.Compact)}
|
Evidence: {JsonSerializer.Serialize(new { evidence.Facts, evidence.Metrics, evidence.Tables, evidence.AssetPlan }, VisualBriefingJson.Canonical)}
|
||||||
""";
|
""";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,9 +257,9 @@ internal sealed class VisualBriefingContentStage(StructuredLlmStageRunner stageR
|
|||||||
authors = "validation",
|
authors = "validation",
|
||||||
protection = "validation",
|
protection = "validation",
|
||||||
},
|
},
|
||||||
}, VisualBriefingJson.Compact);
|
}, VisualBriefingJson.Canonical);
|
||||||
|
|
||||||
var validationData = JsonSerializer.SerializeToElement(data, VisualBriefingJson.Compact);
|
var validationData = JsonSerializer.SerializeToElement(data, VisualBriefingJson.Canonical);
|
||||||
VisualBriefingCompilerInvariant.Guard(VisualBriefingBuildStage.CONTENT,
|
VisualBriefingCompilerInvariant.Guard(VisualBriefingBuildStage.CONTENT,
|
||||||
VisualBriefingArtifactService.ValidateGeneratedParts(
|
VisualBriefingArtifactService.ValidateGeneratedParts(
|
||||||
manifest,
|
manifest,
|
||||||
@ -353,7 +353,7 @@ internal sealed class VisualBriefingContentStage(StructuredLlmStageRunner stageR
|
|||||||
ControlId = $"mwai-filter-{index}",
|
ControlId = $"mwai-filter-{index}",
|
||||||
ComponentId = component.ComponentId,
|
ComponentId = component.ComponentId,
|
||||||
Kind = VisualBriefingControlKind.FILTER,
|
Kind = VisualBriefingControlKind.FILTER,
|
||||||
InitialValue = JsonSerializer.SerializeToElement(SHOW_ALL_VALUE, VisualBriefingJson.Compact),
|
InitialValue = JsonSerializer.SerializeToElement(SHOW_ALL_VALUE, VisualBriefingJson.Canonical),
|
||||||
Options = options,
|
Options = options,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ internal static class VisualBriefingData
|
|||||||
var dictionary = data.EnumerateObject()
|
var dictionary = data.EnumerateObject()
|
||||||
.Where(property => property.Name is not "_mwai")
|
.Where(property => property.Name is not "_mwai")
|
||||||
.ToDictionary(property => property.Name, property => property.Value.Clone(), StringComparer.Ordinal);
|
.ToDictionary(property => property.Name, property => property.Value.Clone(), StringComparer.Ordinal);
|
||||||
return JsonSerializer.SerializeToElement(dictionary, VisualBriefingJson.Compact);
|
return JsonSerializer.SerializeToElement(dictionary, VisualBriefingJson.Canonical);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -47,11 +47,11 @@ internal sealed class VisualBriefingEvidenceStage(StructuredLlmStageRunner stage
|
|||||||
|
|
||||||
var response = run.Response!;
|
var response = run.Response!;
|
||||||
var payloadHash = VisualBriefingHashing.ComputeSections(
|
var payloadHash = VisualBriefingHashing.ComputeSections(
|
||||||
JsonSerializer.Serialize(response.Facts, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(response.Facts, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(response.Metrics, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(response.Metrics, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(response.Tables, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(response.Tables, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(response.SourceCoverage, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(response.SourceCoverage, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(response.AssetPlan, VisualBriefingJson.Compact));
|
JsonSerializer.Serialize(response.AssetPlan, VisualBriefingJson.Canonical));
|
||||||
|
|
||||||
var artifact = new VisualBriefingEvidenceArtifact
|
var artifact = new VisualBriefingEvidenceArtifact
|
||||||
{
|
{
|
||||||
@ -124,8 +124,8 @@ internal sealed class VisualBriefingEvidenceStage(StructuredLlmStageRunner stage
|
|||||||
return $"""
|
return $"""
|
||||||
Target language: {manifest.Settings.TargetLanguage.PromptGeneralPurpose(manifest.Settings.CustomTargetLanguage)}
|
Target language: {manifest.Settings.TargetLanguage.PromptGeneralPurpose(manifest.Settings.CustomTargetLanguage)}
|
||||||
Scope instruction: {manifest.Settings.Instruction}
|
Scope instruction: {manifest.Settings.Instruction}
|
||||||
Sources, in the same order as the attached files: {JsonSerializer.Serialize(sources, VisualBriefingJson.Compact)}
|
Sources, in the same order as the attached files: {JsonSerializer.Serialize(sources, VisualBriefingJson.Canonical)}
|
||||||
Media transcripts: {JsonSerializer.Serialize(transcripts, VisualBriefingJson.Compact)}
|
Media transcripts: {JsonSerializer.Serialize(transcripts, VisualBriefingJson.Canonical)}
|
||||||
""";
|
""";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ internal static class VisualBriefingInteractionCompiler
|
|||||||
controls,
|
controls,
|
||||||
state,
|
state,
|
||||||
formulas = formulaMap,
|
formulas = formulaMap,
|
||||||
}, VisualBriefingJson.Compact);
|
}, VisualBriefingJson.Canonical);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -16,27 +16,27 @@ namespace AIStudio.Assistants.VisualBriefing;
|
|||||||
internal static class VisualBriefingJson
|
internal static class VisualBriefingJson
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets compact canonical JSON options.
|
/// Gets the frozen options whose byte output is hashed into stored briefings.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Treat these options as frozen. Their exact bytes are hashed into stored briefings: the artifact
|
/// Treat these options as frozen. Their exact bytes are hashed into stored briefings: the artifact
|
||||||
/// header is serialized into the briefing document, and reading that document back re-serializes the
|
/// header is serialized into the briefing document, and reading that document back re-serializes the
|
||||||
/// header to recompute the document hash. Every build stage likewise hashes its serialized output to
|
/// header to recompute the document hash. Every build stage likewise hashes its serialized output,
|
||||||
/// decide what a later build may reuse. Any change here — a converter, a naming policy, an encoder —
|
/// and a mismatch makes the store discard the stored artifact. Any change here — a converter, a
|
||||||
/// therefore invalidates every briefing that was ever written, which surfaces as a failed integrity
|
/// naming policy, an encoder — therefore invalidates every briefing that was ever written, which
|
||||||
/// check rather than as a build error. This is why enums stay numeric here even though the persisted
|
/// surfaces as a failed integrity check rather than as a build error. This is why enums stay numeric
|
||||||
/// manifest writes their member names.
|
/// here even though the persisted manifest writes their member names.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal static JsonSerializerOptions Compact { get; } = Create(writeIndented: false, enumsAsText: false);
|
internal static JsonSerializerOptions Canonical { get; } = Create(writeIndented: false, enumsAsText: false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets indented persistence JSON options.
|
/// Gets the options for files that are read back by name rather than by hash.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// These options are free to evolve, because nothing hashes their output. They write the briefing
|
/// These options are free to evolve, because nothing hashes their output. They write the briefing
|
||||||
/// manifest and the diagnostics clipboard text, where readable enum names are worth having.
|
/// manifest and the diagnostics clipboard text, where readable enum names are worth having.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal static JsonSerializerOptions Indented { get; } = Create(writeIndented: true, enumsAsText: true);
|
internal static JsonSerializerOptions Persistence { get; } = Create(writeIndented: true, enumsAsText: true);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates the shared JSON configuration.
|
/// Creates the shared JSON configuration.
|
||||||
|
|||||||
@ -61,7 +61,7 @@ internal sealed class VisualBriefingLayoutCompiler
|
|||||||
reset = content.ResetLabel,
|
reset = content.ResetLabel,
|
||||||
brand = "MindWork AI Studio",
|
brand = "MindWork AI Studio",
|
||||||
},
|
},
|
||||||
}, VisualBriefingJson.Compact);
|
}, VisualBriefingJson.Canonical);
|
||||||
|
|
||||||
var html = CompileNode(layout, sections, components, content, true);
|
var html = CompileNode(layout, sections, components, content, true);
|
||||||
var css = CompileCss(profile, layout);
|
var css = CompileCss(profile, layout);
|
||||||
|
|||||||
@ -132,5 +132,5 @@ public sealed class VisualBriefingOperationDiagnostics
|
|||||||
/// Serializes the diagnostics without user content.
|
/// Serializes the diagnostics without user content.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A compact JSON document suitable for the clipboard.</returns>
|
/// <returns>A compact JSON document suitable for the clipboard.</returns>
|
||||||
public string ToClipboardText() => JsonSerializer.Serialize(this, VisualBriefingJson.Indented);
|
public string ToClipboardText() => JsonSerializer.Serialize(this, VisualBriefingJson.Persistence);
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ internal sealed class VisualBriefingPlanStage(StructuredLlmStageRunner stageRunn
|
|||||||
await VisualBriefingEvidenceStage.FailAsync(store, build, stage, run, VisualBriefingValidationRule.REFERENCE_INVALID, token);
|
await VisualBriefingEvidenceStage.FailAsync(store, build, stage, run, VisualBriefingValidationRule.REFERENCE_INVALID, token);
|
||||||
|
|
||||||
var sections = run.Response!.Sections;
|
var sections = run.Response!.Sections;
|
||||||
var payload = JsonSerializer.Serialize(sections, VisualBriefingJson.Compact);
|
var payload = JsonSerializer.Serialize(sections, VisualBriefingJson.Canonical);
|
||||||
|
|
||||||
var structuralSignature = VisualBriefingHashing.Compute(string.Join('\u001f', sections.Select(section => $"{section.SectionId}:{section.Role}:{section.TitleSlotId}:{section.SummarySlotId}")
|
var structuralSignature = VisualBriefingHashing.Compute(string.Join('\u001f', sections.Select(section => $"{section.SectionId}:{section.Role}:{section.TitleSlotId}:{section.SummarySlotId}")
|
||||||
.Concat(sections.SelectMany(section => section.Components)
|
.Concat(sections.SelectMany(section => section.Components)
|
||||||
@ -113,6 +113,6 @@ internal sealed class VisualBriefingPlanStage(StructuredLlmStageRunner stageRunn
|
|||||||
$"""
|
$"""
|
||||||
Audience: {manifest.Settings.AudienceProfile}; {manifest.Settings.AudienceAgeGroup}; {manifest.Settings.AudienceOrganizationalLevel}; {manifest.Settings.AudienceExpertise}
|
Audience: {manifest.Settings.AudienceProfile}; {manifest.Settings.AudienceAgeGroup}; {manifest.Settings.AudienceOrganizationalLevel}; {manifest.Settings.AudienceExpertise}
|
||||||
Scope instruction: {manifest.Settings.Instruction}
|
Scope instruction: {manifest.Settings.Instruction}
|
||||||
Evidence: {JsonSerializer.Serialize(new { evidence.Facts, evidence.Metrics, evidence.Tables, evidence.AssetPlan }, VisualBriefingJson.Compact)}
|
Evidence: {JsonSerializer.Serialize(new { evidence.Facts, evidence.Metrics, evidence.Tables, evidence.AssetPlan }, VisualBriefingJson.Canonical)}
|
||||||
""";
|
""";
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ internal sealed class VisualBriefingPresentationStage(StructuredLlmStageRunner s
|
|||||||
|
|
||||||
var compiled = VisualBriefingLayoutCompiler.Compile(plan, content, run.Response.Layout, run.Response.Profile);
|
var compiled = VisualBriefingLayoutCompiler.Compile(plan, content, run.Response.Layout, run.Response.Profile);
|
||||||
var payloadHash = VisualBriefingHashing.ComputeSections(
|
var payloadHash = VisualBriefingHashing.ComputeSections(
|
||||||
JsonSerializer.Serialize(run.Response.Layout, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(run.Response.Layout, VisualBriefingJson.Canonical),
|
||||||
run.Response.Profile.ToString(),
|
run.Response.Profile.ToString(),
|
||||||
compiled.TemplateHash,
|
compiled.TemplateHash,
|
||||||
compiled.CssHash);
|
compiled.CssHash);
|
||||||
@ -114,7 +114,7 @@ internal sealed class VisualBriefingPresentationStage(StructuredLlmStageRunner s
|
|||||||
|
|
||||||
await store.SaveBuildAsync(build, token);
|
await store.SaveBuildAsync(build, token);
|
||||||
progressService.Publish(build);
|
progressService.Publish(build);
|
||||||
logger.LogInformation("Visual briefing design completed. OperationId={OperationId} BuildId={BuildId} LayoutHash={LayoutHash} TemplateHash={TemplateHash} CssHash={CssHash}", build.OperationId, build.BuildId, VisualBriefingHashing.Compute(JsonSerializer.Serialize(artifact.Layout, VisualBriefingJson.Compact)), artifact.TemplateHash, artifact.CssHash);
|
logger.LogInformation("Visual briefing design completed. OperationId={OperationId} BuildId={BuildId} LayoutHash={LayoutHash} TemplateHash={TemplateHash} CssHash={CssHash}", build.OperationId, build.BuildId, VisualBriefingHashing.Compute(JsonSerializer.Serialize(artifact.Layout, VisualBriefingJson.Canonical)), artifact.TemplateHash, artifact.CssHash);
|
||||||
|
|
||||||
return artifact;
|
return artifact;
|
||||||
}
|
}
|
||||||
@ -150,9 +150,9 @@ internal sealed class VisualBriefingPresentationStage(StructuredLlmStageRunner s
|
|||||||
authors = "validation",
|
authors = "validation",
|
||||||
protection = "validation",
|
protection = "validation",
|
||||||
},
|
},
|
||||||
}, VisualBriefingJson.Compact);
|
}, VisualBriefingJson.Canonical);
|
||||||
|
|
||||||
var validationData = JsonSerializer.SerializeToElement(data, VisualBriefingJson.Compact);
|
var validationData = JsonSerializer.SerializeToElement(data, VisualBriefingJson.Canonical);
|
||||||
VisualBriefingCompilerInvariant.Guard(VisualBriefingBuildStage.DESIGN,
|
VisualBriefingCompilerInvariant.Guard(VisualBriefingBuildStage.DESIGN,
|
||||||
VisualBriefingArtifactService.ValidateGeneratedParts(manifest, validationData, compiled.TemplateHtml, compiled.Css, content.Charts.Count > 0));
|
VisualBriefingArtifactService.ValidateGeneratedParts(manifest, validationData, compiled.TemplateHtml, compiled.Css, content.Charts.Count > 0));
|
||||||
|
|
||||||
@ -187,12 +187,12 @@ internal sealed class VisualBriefingPresentationStage(StructuredLlmStageRunner s
|
|||||||
|
|
||||||
private static string BuildPrompt(VisualBriefingManifest manifest, VisualBriefingPlanArtifact plan, VisualBriefingPresentationArtifact? parent)
|
private static string BuildPrompt(VisualBriefingManifest manifest, VisualBriefingPlanArtifact plan, VisualBriefingPresentationArtifact? parent)
|
||||||
{
|
{
|
||||||
var parentJson = parent is null ? "none" : JsonSerializer.Serialize(new { parent.Layout, parent.Profile }, VisualBriefingJson.Compact);
|
var parentJson = parent is null ? "none" : JsonSerializer.Serialize(new { parent.Layout, parent.Profile }, VisualBriefingJson.Canonical);
|
||||||
return $"""
|
return $"""
|
||||||
Operation: {(parent is null ? "CREATE_DESIGN" : "CHANGE_DESIGN")}
|
Operation: {(parent is null ? "CREATE_DESIGN" : "CHANGE_DESIGN")}
|
||||||
Design instruction: {manifest.Settings.Instruction}
|
Design instruction: {manifest.Settings.Instruction}
|
||||||
Planned sections and components:
|
Planned sections and components:
|
||||||
{JsonSerializer.Serialize(plan.Sections, VisualBriefingJson.Compact)}
|
{JsonSerializer.Serialize(plan.Sections, VisualBriefingJson.Canonical)}
|
||||||
Parent design:
|
Parent design:
|
||||||
{parentJson}
|
{parentJson}
|
||||||
""";
|
""";
|
||||||
|
|||||||
@ -164,11 +164,11 @@ public sealed partial class VisualBriefingStore
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
var hash = VisualBriefingHashing.ComputeSections(
|
var hash = VisualBriefingHashing.ComputeSections(
|
||||||
JsonSerializer.Serialize(artifact.Facts, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.Facts, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.Metrics, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.Metrics, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.Tables, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.Tables, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.SourceCoverage, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.SourceCoverage, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.AssetPlan, VisualBriefingJson.Compact));
|
JsonSerializer.Serialize(artifact.AssetPlan, VisualBriefingJson.Canonical));
|
||||||
|
|
||||||
return string.Equals(hash, artifact.PayloadHash, StringComparison.Ordinal) ? artifact : null;
|
return string.Equals(hash, artifact.PayloadHash, StringComparison.Ordinal) ? artifact : null;
|
||||||
}
|
}
|
||||||
@ -217,7 +217,7 @@ public sealed partial class VisualBriefingStore
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
var hash = VisualBriefingHashing.ComputeSections(
|
var hash = VisualBriefingHashing.ComputeSections(
|
||||||
JsonSerializer.Serialize(artifact.Sections, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.Sections, VisualBriefingJson.Canonical),
|
||||||
artifact.StructuralSignature);
|
artifact.StructuralSignature);
|
||||||
|
|
||||||
return string.Equals(hash, artifact.PayloadHash, StringComparison.Ordinal) ? artifact : null;
|
return string.Equals(hash, artifact.PayloadHash, StringComparison.Ordinal) ? artifact : null;
|
||||||
@ -273,15 +273,15 @@ public sealed partial class VisualBriefingStore
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
var payloadHash = VisualBriefingHashing.ComputeSections(
|
var payloadHash = VisualBriefingHashing.ComputeSections(
|
||||||
JsonSerializer.Serialize(artifact.Slots, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.Slots, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.Charts, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.Charts, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.Controls, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.Controls, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.Formulas, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.Formulas, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.AccessibilityTexts, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.AccessibilityTexts, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.SourceReferences, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.SourceReferences, VisualBriefingJson.Canonical),
|
||||||
artifact.ResetLabel,
|
artifact.ResetLabel,
|
||||||
JsonSerializer.Serialize(artifact.SourceCoverage, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.SourceCoverage, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(artifact.AssetPlan, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.AssetPlan, VisualBriefingJson.Canonical),
|
||||||
artifact.StructuralSignature);
|
artifact.StructuralSignature);
|
||||||
|
|
||||||
return string.Equals(payloadHash, artifact.PayloadHash, StringComparison.Ordinal) ? artifact : null;
|
return string.Equals(payloadHash, artifact.PayloadHash, StringComparison.Ordinal) ? artifact : null;
|
||||||
@ -336,7 +336,7 @@ public sealed partial class VisualBriefingStore
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
var payloadHash = VisualBriefingHashing.ComputeSections(
|
var payloadHash = VisualBriefingHashing.ComputeSections(
|
||||||
JsonSerializer.Serialize(artifact.Layout, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(artifact.Layout, VisualBriefingJson.Canonical),
|
||||||
artifact.Profile.ToString(),
|
artifact.Profile.ToString(),
|
||||||
artifact.TemplateHash,
|
artifact.TemplateHash,
|
||||||
artifact.CssHash);
|
artifact.CssHash);
|
||||||
|
|||||||
@ -504,15 +504,15 @@ public sealed partial class VisualBriefingStore
|
|||||||
|
|
||||||
// Section order and count must match ReadContentArtifactAsync exactly:
|
// Section order and count must match ReadContentArtifactAsync exactly:
|
||||||
var contentHash = VisualBriefingHashing.ComputeSections(
|
var contentHash = VisualBriefingHashing.ComputeSections(
|
||||||
JsonSerializer.Serialize(importedSlots, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(importedSlots, VisualBriefingJson.Canonical),
|
||||||
"[]",
|
"[]",
|
||||||
"[]",
|
"[]",
|
||||||
"[]",
|
"[]",
|
||||||
"{}",
|
"{}",
|
||||||
"{}",
|
"{}",
|
||||||
"Reset",
|
"Reset",
|
||||||
JsonSerializer.Serialize(coverage, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(coverage, VisualBriefingJson.Canonical),
|
||||||
JsonSerializer.Serialize(assetPlan, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(assetPlan, VisualBriefingJson.Canonical),
|
||||||
structuralSignature);
|
structuralSignature);
|
||||||
|
|
||||||
var content = new VisualBriefingContentArtifact
|
var content = new VisualBriefingContentArtifact
|
||||||
@ -551,7 +551,7 @@ public sealed partial class VisualBriefingStore
|
|||||||
ArtifactId = Guid.NewGuid(),
|
ArtifactId = Guid.NewGuid(),
|
||||||
CreatedAtUtc = DateTimeOffset.UtcNow,
|
CreatedAtUtc = DateTimeOffset.UtcNow,
|
||||||
PayloadHash = VisualBriefingHashing.ComputeSections(
|
PayloadHash = VisualBriefingHashing.ComputeSections(
|
||||||
JsonSerializer.Serialize(importedLayout, VisualBriefingJson.Compact),
|
JsonSerializer.Serialize(importedLayout, VisualBriefingJson.Canonical),
|
||||||
VisualBriefingDesignProfile.EDITORIAL.ToString(),
|
VisualBriefingDesignProfile.EDITORIAL.ToString(),
|
||||||
templateHash,
|
templateHash,
|
||||||
cssHash),
|
cssHash),
|
||||||
@ -607,7 +607,7 @@ public sealed partial class VisualBriefingStore
|
|||||||
var businessData = VisualBriefingHashing.CanonicalJson(VisualBriefingData.RemoveProtectedData(parts.Data));
|
var businessData = VisualBriefingHashing.CanonicalJson(VisualBriefingData.RemoveProtectedData(parts.Data));
|
||||||
var assets = JsonSerializer.Serialize(
|
var assets = JsonSerializer.Serialize(
|
||||||
VisualBriefingData.ExtractAssets(parts.Data),
|
VisualBriefingData.ExtractAssets(parts.Data),
|
||||||
VisualBriefingJson.Compact);
|
VisualBriefingJson.Canonical);
|
||||||
|
|
||||||
return new(
|
return new(
|
||||||
VisualBriefingHashing.Compute(businessData),
|
VisualBriefingHashing.Compute(businessData),
|
||||||
|
|||||||
@ -45,7 +45,7 @@ public sealed partial class VisualBriefingStore(
|
|||||||
private const string TRANSCRIPTS_DIRECTORY_NAME = "transcripts";
|
private const string TRANSCRIPTS_DIRECTORY_NAME = "transcripts";
|
||||||
|
|
||||||
/// <summary>Gets the shared persistence JSON options.</summary>
|
/// <summary>Gets the shared persistence JSON options.</summary>
|
||||||
private static readonly JsonSerializerOptions JSON_OPTIONS = VisualBriefingJson.Indented;
|
private static readonly JsonSerializerOptions JSON_OPTIONS = VisualBriefingJson.Persistence;
|
||||||
|
|
||||||
/// <summary>Stores per-project process locks.</summary>
|
/// <summary>Stores per-project process locks.</summary>
|
||||||
private readonly ConcurrentDictionary<Guid, SemaphoreSlim> briefingLocks = [];
|
private readonly ConcurrentDictionary<Guid, SemaphoreSlim> briefingLocks = [];
|
||||||
|
|||||||
@ -184,7 +184,7 @@ internal static partial class VisualBriefingStructuredResponseProcessor
|
|||||||
T? parsed;
|
T? parsed;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
parsed = JsonSerializer.Deserialize<T>(candidate.Json, VisualBriefingJson.Compact);
|
parsed = JsonSerializer.Deserialize<T>(candidate.Json, VisualBriefingJson.Canonical);
|
||||||
}
|
}
|
||||||
catch (JsonException exception)
|
catch (JsonException exception)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -685,7 +685,7 @@ internal static partial class VisualBriefingValidation
|
|||||||
|
|
||||||
private static bool ContainsForbidden<T>(T value)
|
private static bool ContainsForbidden<T>(T value)
|
||||||
{
|
{
|
||||||
var json = JsonSerializer.SerializeToElement(value, VisualBriefingJson.Compact);
|
var json = JsonSerializer.SerializeToElement(value, VisualBriefingJson.Canonical);
|
||||||
return ContainsForbiddenElement(json);
|
return ContainsForbiddenElement(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user