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);
}
}