Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@ public static class Defaults
/// in the <see cref="IResponseCacheProvider"/>'s cache before they are considered expired and evicted.
/// </summary>
public static TimeSpan DefaultTimeToLiveForCacheEntries { get; } = TimeSpan.FromDays(14);

/// <summary>
/// Defines the version number for the reporting format. If and when the serialized format undergoes
/// breaking changes, this number will be incremented.
/// </summary>
internal const int ReportingFormatVersion = 1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ namespace Microsoft.Extensions.AI.Evaluation.Reporting;
/// The <see cref="Evaluation.EvaluationResult"/> for the <see cref="ScenarioRun"/> corresponding to the
/// <see cref="ScenarioRunResult"/> being constructed.
/// </param>
/// <param name="formatVersion">The version of the format used to persist the current <see cref="ScenarioRunResult"/>.</param>
[method: JsonConstructor]
public sealed class ScenarioRunResult(
string scenarioName,
Expand All @@ -45,7 +46,8 @@ public sealed class ScenarioRunResult(
DateTime creationTime,
IList<ChatMessage> messages,
ChatResponse modelResponse,
EvaluationResult evaluationResult)
EvaluationResult evaluationResult,
int? formatVersion = null)
{
/// <summary>
/// Initializes a new instance of the <see cref="ScenarioRunResult"/> class.
Expand Down Expand Up @@ -81,6 +83,11 @@ public ScenarioRunResult(
{
}

/// <summary>
/// Gets or sets the version of the format used to persist the current <see cref="ScenarioRunResult"/>.
/// </summary>
public int? FormatVersion { get; set; } = formatVersion ?? Defaults.ReportingFormatVersion;

/// <summary>
/// Gets or sets the <see cref="ScenarioRun.ScenarioName"/>.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ protected override async Task WriteCacheStreamingAsync(string key, IReadOnlyList
/// The generated cache key is not guaranteed to be stable across releases of the library.
/// </para>
/// </remarks>
protected override string GetCacheKey(params ReadOnlySpan<object?> values) =>
AIJsonUtilities.HashDataToString(values, _jsonSerializerOptions);
protected override string GetCacheKey(params ReadOnlySpan<object?> values)
{
// Bump the cache version to invalidate existing caches if the serialization format changes in a breaking way.
const int CacheVersion = 1;

return AIJsonUtilities.HashDataToString([CacheVersion, .. values], _jsonSerializerOptions);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public void SerializeScenarioRunResult()
messages: [new ChatMessage(ChatRole.User, "prompt")],
modelResponse: new ChatResponse(new ChatMessage(ChatRole.Assistant, "response")),
evaluationResult: new EvaluationResult(booleanMetric, numericMetric, stringMetric, metricWithNoValue));
Assert.Equal(Defaults.ReportingFormatVersion, entry.FormatVersion);

string json = JsonSerializer.Serialize(entry, SerializerContext.Default.ScenarioRunResult);
ScenarioRunResult? deserialized = JsonSerializer.Deserialize<ScenarioRunResult>(json, SerializerContext.Default.ScenarioRunResult);
Expand All @@ -49,6 +50,7 @@ public void SerializeScenarioRunResult()
Assert.Equal(entry.CreationTime, deserialized.CreationTime);
Assert.True(entry.Messages.SequenceEqual(deserialized.Messages, ChatMessageComparer.Instance));
Assert.Equal(entry.ModelResponse, deserialized.ModelResponse, ChatResponseComparer.Instance);
Assert.Equal(entry.FormatVersion, deserialized.FormatVersion);

ValidateEquivalence(entry.EvaluationResult, deserialized.EvaluationResult);
}
Expand Down
Loading