using System.Text.Json.Serialization; using AIStudio.Settings.DataModel; namespace AIStudio.Assistants.ModelComparison; /// /// A comparison series: two models compared on real tasks of the user, over days or weeks, with the same profile, /// tools, and data sources for both. /// /// /// The series keeps the providers by their IDs, to ask them, and the identities of their models as they were when the /// series began, so that a provider whose model changed meanwhile is noticed rather than compared under a wrong name. /// Its chats lie in the folder of the series, see ModelComparisonStore, and stay readable there. /// public sealed record ModelComparisonSeries { /// /// The ID of the series, which names its folder. /// public Guid Id { get; set; } /// /// The name the user gave the series. /// public string Name { get; set; } = string.Empty; /// /// When the user began the series, in UTC. /// public DateTimeOffset CreatedAtUtc { get; set; } /// /// The ID of the provider of the first model. /// public string FirstProviderId { get; set; } = string.Empty; /// /// The ID of the provider of the second model. /// public string SecondProviderId { get; set; } = string.Empty; /// /// The first model, as it was when the series began. /// public ModelComparisonModelIdentity First { get; set; } = new(); /// /// The second model, as it was when the series began. /// public ModelComparisonModelIdentity Second { get; set; } = new(); /// /// The ID of the provider of the judge, or empty without a judge. /// public string JudgeProviderId { get; set; } = string.Empty; /// /// The judge, as it was when the series began, or null without a judge. /// public ModelComparisonModelIdentity? Judge { get; set; } /// /// The expectations, values, and goals of the user, by which the judge decides, see ModelComparisonJudgeExpectations; /// empty when the user confirmed that the judge may decide by its own standards. Fixed with the series like its /// models, so that the judge decides every task by the same standards. /// public string JudgeInstructions { get; set; } = string.Empty; /// /// The ID of the profile both chats use. /// public string ProfileId { get; set; } = string.Empty; /// /// The tools both chats may use. /// public List ToolIds { get; set; } = []; /// /// The IDs of the data sources both chats may search. /// public List DataSourceIds { get; set; } = []; /// /// How both chats search the data sources, or null without data sources. The same for both, so that neither model /// gets passages which the other one has to look for itself. /// public DataSourceRetrievalMode? RetrievalMode { get; set; } /// /// Whether the user saw the result of the series, which names the models. Tasks decided afterward are no longer /// blind. /// public bool IsResolved { get; set; } /// /// When the user saw the result of the series first, in UTC, or null before. /// public DateTimeOffset? ResolvedAtUtc { get; set; } /// /// The tasks of the series, in the order they were started. /// public List Tasks { get; set; } = []; /// /// When the user last worked on the series, in UTC. /// [JsonIgnore] public DateTimeOffset LastActivityUtc => this.Tasks .Select(task => task.FinishedAtUtc ?? task.StartedAtUtc) .Append(this.CreatedAtUtc) .Max(); /// /// The task the user works on right now, or null when every task is decided. /// [JsonIgnore] public ModelComparisonSeriesTask? OpenTask => this.Tasks.LastOrDefault(task => task.State is not ModelComparisonSeriesTaskState.DONE); }