using System.Text.Json; namespace AIStudio.Assistants.VisualBriefing; /// /// Contains user-safe technical details for the most recent operation. /// public sealed class VisualBriefingOperationDiagnostics { /// /// Gets or sets the operation identifier. /// public Guid OperationId { get; set; } /// /// Gets or sets the build identifier. /// public Guid BuildId { get; set; } /// /// Gets or sets the current or failed stage. /// public VisualBriefingBuildStage Stage { get; set; } /// /// Gets or sets the failure code. /// public VisualBriefingFailureCode FailureCode { get; set; } /// /// Gets or sets the stable validation rule. /// public VisualBriefingValidationRule ValidationRule { get; set; } /// /// Gets or sets the AI Studio artifact version. /// public int ArtifactVersion { get; set; } = VisualBriefingVersions.ARTIFACT; /// /// Gets or sets the data schema version. /// public int SchemaVersion { get; set; } = VisualBriefingVersions.SCHEMA; /// /// Gets or sets the runtime version. /// public int RuntimeVersion { get; set; } = VisualBriefingVersions.RUNTIME; /// /// Gets or sets the provider family. /// public string ProviderFamily { get; set; } = string.Empty; /// /// Gets or sets the selected model. /// public string Model { get; set; } = string.Empty; /// /// Gets or sets the safe structured-response diagnostic. /// public VisualBriefingStructuredResponseDiagnostic? StructuredResponse { get; set; } /// /// Gets or sets the operation start time. /// public DateTimeOffset StartedAtUtc { get; set; } /// /// Gets or sets the operation finish time. /// public DateTimeOffset? FinishedAtUtc { get; set; } /// /// Gets or sets safe content hashes used for support diagnostics. /// public Dictionary ContentHashes { get; set; } = new(StringComparer.Ordinal); /// /// Gets or sets safe intermediate artifact identifiers for support diagnostics. /// public Dictionary ArtifactIds { get; set; } = new(StringComparer.Ordinal); /// /// Reconstructs clipboard-safe diagnostics from a persistent build record. /// /// The persistent build record. /// The reconstructed diagnostics. public static VisualBriefingOperationDiagnostics FromBuildRecord(VisualBriefingBuildRecord build) { var latestStage = build.Failure?.Stage ?? build.Stages .Where(stage => stage.Status is not VisualBriefingBuildStageStatus.NOT_STARTED) .OrderByDescending(stage => stage.Stage) .FirstOrDefault()?.Stage ?? VisualBriefingBuildStage.SOURCE_PREPARATION; return new() { OperationId = build.OperationId, BuildId = build.BuildId, Stage = latestStage, FailureCode = build.Failure?.Code ?? VisualBriefingFailureCode.NONE, ValidationRule = build.Failure?.ValidationRule ?? VisualBriefingValidationRule.NONE, StructuredResponse = build.Failure?.StructuredResponse, ProviderFamily = build.ProviderFamily, Model = build.Model, StartedAtUtc = build.CreatedAtUtc, FinishedAtUtc = build.Status is VisualBriefingBuildStatus.ACTIVE ? null : build.UpdatedAtUtc, ContentHashes = build.Stages .Where(stage => !string.IsNullOrWhiteSpace(stage.OutputHash)) .GroupBy(stage => stage.Stage) .ToDictionary( group => group.Key.ToString(), group => group.Last().OutputHash, StringComparer.Ordinal), ArtifactIds = new Dictionary(StringComparer.Ordinal) { ["evidence"] = build.EvidenceArtifactId ?? Guid.Empty, ["plan"] = build.PlanArtifactId ?? Guid.Empty, ["content"] = build.ContentArtifactId ?? Guid.Empty, ["design"] = build.PresentationArtifactId ?? Guid.Empty, } .Where(item => item.Value != Guid.Empty) .ToDictionary(item => item.Key, item => item.Value, StringComparer.Ordinal), }; } /// /// Serializes the diagnostics without user content. /// /// A compact JSON document suitable for the clipboard. public string ToClipboardText() => JsonSerializer.Serialize(this, VisualBriefingJson.Persistence); }