using AIStudio.Provider; using AIStudio.Settings; using AIStudio.Settings.DataModel; namespace AIStudio.Tools.RAG; /// /// What a chat has to require from now on, because passages of data sources reached the model. /// /// /// Both ways of searching the data sources ask here, Semantic Search and the classic RAG process, /// so that both demand the same of the same data sources: two answers which drift apart would leave /// one of the ways open. /// /// The provider confidence the chat requires from now on. /// The data security the chat requires from now on; NOT_SPECIFIED leaves it as it was. /// Where the chat may still send data, and which data source demands it. public sealed record DataSourceRequirements(ConfidenceLevel Confidence, DataSourceSecurity Security, OutboundDataRequirement OutboundData) { /// /// Demands nothing: what a search requires which brought no passage into the chat. /// public static readonly DataSourceRequirements NONE = new(ConfidenceLevel.NONE, DataSourceSecurity.NOT_SPECIFIED, OutboundDataRequirement.NONE); /// /// What the passages of these data sources demand. /// /// /// Only the data sources with passages count: a data source which found nothing brought nothing /// into the chat. A data source which only self-hosted providers may use restricts the chat to /// those. Of the outbound data restrictions, the strictest wins, see /// DataSourceOutboundDataExtensions.GetEffectiveOutboundDataRestriction. Of several equally strict /// data sources, the first in their fixed order is named, see DataSourceOrderExtensions.InFixedOrder, /// so that the name does not depend on the order in which one way of searching got them. /// /// The data sources searched. /// How many passages of each data source reached the model, in the same order. /// The least strict outbound data restriction the organization allows, see DataSourceSecuritySettings.MinimumOutboundDataRestriction. /// What the chat requires from now on; NONE when no data source brought a passage. /// The counts do not match the data sources. public static DataSourceRequirements Of(IReadOnlyList dataSources, IReadOnlyList passageCounts, OutboundDataRestriction organizationMinimum) { if (passageCounts.Count != dataSources.Count) throw new ArgumentException($"There are {passageCounts.Count} passage counts for {dataSources.Count} data sources.", nameof(passageCounts)); var contributingDataSources = dataSources.Where((_, index) => passageCounts[index] > 0).InFixedOrder(); if (contributingDataSources.Count == 0) return NONE; var outboundData = OutboundDataRequirement.NONE; foreach (var dataSource in contributingDataSources) outboundData = outboundData.StricterOf(new(dataSource.GetEffectiveOutboundDataRestriction(organizationMinimum), OutboundDataOrigin.DATA_SOURCE, dataSource.Id)); var requiresSelfHosted = contributingDataSources.OfType().Any(dataSource => dataSource.SecurityPolicy is DataSourceSecurity.SELF_HOSTED); return new(contributingDataSources.GetRequiredConfidenceLevel(), requiresSelfHosted ? DataSourceSecurity.SELF_HOSTED : DataSourceSecurity.ALLOW_ANY, outboundData); } }