mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-05 02:27:21 +00:00
Adopted further C# 14 and .NET 10 features (#1158)
This commit is contained in:
1 parent
f649febf88
commit
f0fa1411c8
40 files changed
+545
-56
No files matched your search
@@ -31,6 +31,9 @@ internal static class VisualBriefingJson
|
||||
/// here even though the persisted manifest writes their member names. Unlike other options of the app,
|
||||
/// these are not made read-only right here, because MWAIS0010 wants nothing but the object creation;
|
||||
/// System.Text.Json locks them with their first use anyway.
|
||||
///
|
||||
/// The answers of the model are read with these options, too, which therefore refuse a field named
|
||||
/// twice. That rule only concerns reading and changes no byte of the output.
|
||||
/// </remarks>
|
||||
[CanonicalJsonConfiguration]
|
||||
internal static JsonSerializerOptions Canonical { get; } = new()
|
||||
@@ -40,6 +43,7 @@ internal static class VisualBriefingJson
|
||||
WriteIndented = false,
|
||||
Encoder = JavaScriptEncoder.Default,
|
||||
UnmappedMemberHandling = JsonUnmappedMemberHandling.Disallow,
|
||||
AllowDuplicateProperties = false,
|
||||
TypeInfoResolver = VisualBriefingCanonicalJsonContext.Default,
|
||||
};
|
||||
|
||||
|
||||
+3
@@ -40,4 +40,7 @@ public enum VisualBriefingStructuredResponseIssueKind
|
||||
|
||||
/// <summary>The parsed response violated a semantic stage contract.</summary>
|
||||
SEMANTIC_CONTRACT_INVALID,
|
||||
|
||||
/// <summary>An object of the response named the same field more than once.</summary>
|
||||
DUPLICATE_FIELD,
|
||||
}
|
||||
+69
-1
@@ -20,7 +20,7 @@ internal static partial class VisualBriefingStructuredResponseProcessor
|
||||
.DisableHtml()
|
||||
.Build();
|
||||
private static readonly NullabilityInfoContext NULLABILITY = new();
|
||||
private static readonly object CONTRACT_LOCK = new();
|
||||
private static readonly Lock CONTRACT_LOCK = new();
|
||||
private static readonly Dictionary<Type, ContractShape> CONTRACTS = [];
|
||||
|
||||
/// <summary>
|
||||
@@ -159,6 +159,18 @@ internal static partial class VisualBriefingStructuredResponseProcessor
|
||||
"The structured response root must be a JSON object.",
|
||||
expected: "JSON object");
|
||||
|
||||
var duplicateIssue = FindDuplicateField(document.RootElement, "$");
|
||||
if (duplicateIssue is not null)
|
||||
return Rejected<T>(
|
||||
candidate,
|
||||
duplicateIssue.Kind,
|
||||
VisualBriefingFailureCode.RESPONSE_JSON_INVALID,
|
||||
VisualBriefingValidationRule.JSON_INVALID,
|
||||
ContractIssueMessage(duplicateIssue),
|
||||
duplicateIssue.Path,
|
||||
fieldName: duplicateIssue.FieldName,
|
||||
expected: duplicateIssue.Expected);
|
||||
|
||||
var contractIssue = Inspect(
|
||||
document.RootElement,
|
||||
GetContract(typeof(T)),
|
||||
@@ -377,6 +389,58 @@ internal static partial class VisualBriefingStructuredResponseProcessor
|
||||
private static long? ToResponseLine(ResponseCandidate candidate, long? candidateLine) =>
|
||||
candidateLine is null ? null : candidate.StartLine + candidateLine;
|
||||
|
||||
/// <summary>
|
||||
/// Finds the first field which an object of the response names a second time.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// JSON allows a name twice, and readers disagree on which of the values counts: the checks below
|
||||
/// see one of them, while the browser which runs the finished briefing may see the other. The
|
||||
/// response is refused instead, and the repair names the field. This looks into every value, also
|
||||
/// into those the contract leaves open, such as the data of a chart.
|
||||
/// </remarks>
|
||||
private static ContractInspectionIssue? FindDuplicateField(JsonElement element, string path)
|
||||
{
|
||||
switch (element.ValueKind)
|
||||
{
|
||||
case JsonValueKind.Object:
|
||||
{
|
||||
var names = new HashSet<string>(StringComparer.Ordinal);
|
||||
foreach (var property in element.EnumerateObject())
|
||||
{
|
||||
var safeField = SafeIdentifier(property.Name);
|
||||
var fieldPath = string.IsNullOrEmpty(safeField) ? path : $"{path}.{safeField}";
|
||||
if (!names.Add(property.Name))
|
||||
return new(
|
||||
VisualBriefingStructuredResponseIssueKind.DUPLICATE_FIELD,
|
||||
fieldPath,
|
||||
safeField,
|
||||
"every field name only once per object");
|
||||
|
||||
var issue = FindDuplicateField(property.Value, fieldPath);
|
||||
if (issue is not null)
|
||||
return issue;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
case JsonValueKind.Array:
|
||||
{
|
||||
var index = 0;
|
||||
foreach (var item in element.EnumerateArray())
|
||||
{
|
||||
var issue = FindDuplicateField(item, $"{path}[{index}]");
|
||||
if (issue is not null)
|
||||
return issue;
|
||||
index++;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static ContractInspectionIssue? Inspect(
|
||||
JsonElement element,
|
||||
ContractShape shape,
|
||||
@@ -496,6 +560,10 @@ internal static partial class VisualBriefingStructuredResponseProcessor
|
||||
$"The model response contains the unknown field '{issue.FieldName}' at {issue.Path}.",
|
||||
VisualBriefingStructuredResponseIssueKind.UNKNOWN_FIELD =>
|
||||
$"The model response contains an unknown field at {issue.Path}.",
|
||||
VisualBriefingStructuredResponseIssueKind.DUPLICATE_FIELD when !string.IsNullOrEmpty(issue.FieldName) =>
|
||||
$"The model response contains the field '{issue.FieldName}' more than once at {issue.Path}.",
|
||||
VisualBriefingStructuredResponseIssueKind.DUPLICATE_FIELD =>
|
||||
$"The model response contains a field more than once at {issue.Path}.",
|
||||
VisualBriefingStructuredResponseIssueKind.REQUIRED_FIELD_MISSING =>
|
||||
$"The required field '{issue.FieldName}' is missing at {issue.Path}.",
|
||||
VisualBriefingStructuredResponseIssueKind.ENUM_VALUE_INVALID =>
|
||||
|
||||
Reference in new issue
Block a user