namespace AIStudio.Assistants.VisualBriefing; /// /// Stores a safe structural diagnostic without model output or user content. /// public sealed class VisualBriefingStructuredResponseDiagnostic { /// /// Gets or sets the stable structural issue kind. /// public VisualBriefingStructuredResponseIssueKind IssueKind { get; set; } /// /// Gets or sets the envelope containing the selected candidate. /// public VisualBriefingStructuredResponseEnvelope Envelope { get; set; } /// /// Gets or sets the one-based candidate index. /// public int CandidateIndex { get; set; } = 1; /// /// Gets or sets the number of eligible candidates in the response. /// public int CandidateCount { get; set; } = 1; /// /// Gets or sets a safe JSON path containing only contract property names, indices, and wildcards. /// public string JsonPath { get; set; } = "$"; /// /// Gets or sets the one-based line in the complete model response. /// public long? LineNumber { get; set; } /// /// Gets or sets the zero-based UTF-8 byte position in the line. /// public long? BytePositionInLine { get; set; } /// /// Gets or sets a sanitized contract field name. /// public string FieldName { get; set; } = string.Empty; /// /// Gets or sets a content-free expected contract shape. /// public string Expected { get; set; } = string.Empty; /// /// Formats the diagnostic for content-free technical details. /// /// A stable semicolon-separated diagnostic. internal string ToTechnicalDetails() { var details = new List { $"StructuredIssue={this.IssueKind}", $"Envelope={this.Envelope}", $"Candidate={this.CandidateIndex}/{this.CandidateCount}", $"JsonPath={this.JsonPath}", }; if (this.LineNumber is not null) details.Add($"Line={this.LineNumber}"); if (this.BytePositionInLine is not null) details.Add($"BytePositionInLine={this.BytePositionInLine}"); if (!string.IsNullOrEmpty(this.FieldName)) details.Add($"Field={this.FieldName}"); if (!string.IsNullOrEmpty(this.Expected)) details.Add($"Expected={this.Expected}"); return string.Join("; ", details); } }