using System.Collections.Concurrent; using System.Text.Json; namespace AIStudio.Assistants.VisualBriefing; /// /// Publishes content-free live build snapshots while persistent records remain authoritative. /// public sealed class VisualBriefingBuildProgressService { private readonly ConcurrentDictionary latest = []; /// /// Raised whenever the latest safe build snapshot changes. /// public event Action? Changed; /// /// Publishes the latest build record for one briefing. /// public void Publish(VisualBriefingBuildRecord build) { var snapshot = JsonSerializer.Deserialize( JsonSerializer.Serialize(build, VisualBriefingJson.Canonical), VisualBriefingJson.Canonical)!; snapshot.Instruction = string.Empty; this.latest[build.BriefingId] = snapshot; this.Changed?.Invoke(build.BriefingId); } /// /// Gets the most recent live snapshot, if one exists. /// public VisualBriefingBuildRecord? GetLatest(Guid briefingId) => this.latest.GetValueOrDefault(briefingId); /// /// Drops the snapshot of a briefing which does not exist anymore. /// /// /// A snapshot is a complete build record. Without this, every briefing which was ever built /// kept one for as long as the app was running. /// /// The identifier of the deleted briefing. public void Forget(Guid briefingId) => this.latest.TryRemove(briefingId, out _); }