mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-08-11 19:52:10 +00:00
Added security checks for confidence levels
This commit is contained in:
parent
3eca153f83
commit
185a99c9ed
@ -140,6 +140,8 @@ public sealed class AgentDataSourceSelection (ILogger<AgentDataSourceSelection>
|
|||||||
//
|
//
|
||||||
|
|
||||||
// We start with the provider currently selected by the user:
|
// We start with the provider currently selected by the user:
|
||||||
|
var requiredDataSecurity = dataSources.AllowedDataSources.GetRequiredSecurityPolicy();
|
||||||
|
var requiredComplianceLevel = dataSources.AllowedDataSources.GetRequiredComplianceLevel();
|
||||||
var agentProvider = this.SettingsManager.GetPreselectedProvider(Tools.Components.AGENT_DATA_SOURCE_SELECTION, provider.Id, true);
|
var agentProvider = this.SettingsManager.GetPreselectedProvider(Tools.Components.AGENT_DATA_SOURCE_SELECTION, provider.Id, true);
|
||||||
if (agentProvider == Settings.Provider.NONE)
|
if (agentProvider == Settings.Provider.NONE)
|
||||||
{
|
{
|
||||||
@ -147,6 +149,12 @@ public sealed class AgentDataSourceSelection (ILogger<AgentDataSourceSelection>
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!agentProvider.AllowsDataSourceAccess(this.SettingsManager, requiredDataSecurity, requiredComplianceLevel))
|
||||||
|
{
|
||||||
|
logger.LogWarning($"The agent for data source selection uses provider '{agentProvider.InstanceName}' with confidence '{agentProvider.GetConfidenceLevel(this.SettingsManager).GetName()}', but the available data sources require data security '{requiredDataSecurity}' and provider confidence '{requiredComplianceLevel.GetName()}'. The agent cannot select data sources.");
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
// Assign the provider settings to the agent:
|
// Assign the provider settings to the agent:
|
||||||
logger.LogInformation($"The agent for the data source selection uses the provider '{agentProvider.InstanceName}' ({agentProvider.UsedLLMProvider.ToName()}, confidence={agentProvider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level.GetName()}).");
|
logger.LogInformation($"The agent for the data source selection uses the provider '{agentProvider.InstanceName}' ({agentProvider.UsedLLMProvider.ToName()}, confidence={agentProvider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level.GetName()}).");
|
||||||
this.ProviderSettings = agentProvider;
|
this.ProviderSettings = agentProvider;
|
||||||
|
|||||||
@ -3,6 +3,7 @@ using System.Text.Json;
|
|||||||
using AIStudio.Chat;
|
using AIStudio.Chat;
|
||||||
using AIStudio.Provider;
|
using AIStudio.Provider;
|
||||||
using AIStudio.Settings;
|
using AIStudio.Settings;
|
||||||
|
using AIStudio.Settings.DataModel;
|
||||||
using AIStudio.Tools.RAG;
|
using AIStudio.Tools.RAG;
|
||||||
using AIStudio.Tools.Services;
|
using AIStudio.Tools.Services;
|
||||||
|
|
||||||
@ -129,19 +130,30 @@ public sealed class AgentRetrievalContextValidation (ILogger<AgentRetrievalConte
|
|||||||
/// you can set the provider once and then call the validation method in parallel.
|
/// you can set the provider once and then call the validation method in parallel.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="provider">The current LLM provider. When the user doesn't preselect an agent provider, the agent uses this provider.</param>
|
/// <param name="provider">The current LLM provider. When the user doesn't preselect an agent provider, the agent uses this provider.</param>
|
||||||
public void SetLLMProvider(IProvider provider)
|
/// <param name="requiredDataSecurity">The data security required by the retrieved data.</param>
|
||||||
|
/// <param name="requiredComplianceLevel">The minimum provider confidence required by the retrieved data.</param>
|
||||||
|
public bool SetLLMProvider(IProvider provider, DataSourceSecurity requiredDataSecurity = DataSourceSecurity.NOT_SPECIFIED, ConfidenceLevel requiredComplianceLevel = ConfidenceLevel.NONE)
|
||||||
{
|
{
|
||||||
// We start with the provider currently selected by the user:
|
// We start with the provider currently selected by the user:
|
||||||
var agentProvider = this.SettingsManager.GetPreselectedProvider(Tools.Components.AGENT_RETRIEVAL_CONTEXT_VALIDATION, provider.Id, true);
|
var agentProvider = this.SettingsManager.GetPreselectedProvider(Tools.Components.AGENT_RETRIEVAL_CONTEXT_VALIDATION, provider.Id, true);
|
||||||
if (agentProvider == Settings.Provider.NONE)
|
if (agentProvider == Settings.Provider.NONE)
|
||||||
{
|
{
|
||||||
logger.LogWarning("No provider is selected for the agent.");
|
logger.LogWarning("No provider is selected for the agent.");
|
||||||
return;
|
this.ProviderSettings = Settings.Provider.NONE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!agentProvider.AllowsDataSourceAccess(this.SettingsManager, requiredDataSecurity, requiredComplianceLevel))
|
||||||
|
{
|
||||||
|
logger.LogWarning($"The agent for retrieval context validation uses provider '{agentProvider.InstanceName}' with confidence '{agentProvider.GetConfidenceLevel(this.SettingsManager).GetName()}', but the retrieved data requires data security '{requiredDataSecurity}' and provider confidence '{requiredComplianceLevel.GetName()}'. The agent cannot validate retrieval contexts.");
|
||||||
|
this.ProviderSettings = Settings.Provider.NONE;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign the provider settings to the agent:
|
// Assign the provider settings to the agent:
|
||||||
logger.LogInformation($"The agent for the retrieval context validation uses the provider '{agentProvider.InstanceName}' ({agentProvider.UsedLLMProvider.ToName()}, confidence={agentProvider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level.GetName()}).");
|
logger.LogInformation($"The agent for the retrieval context validation uses the provider '{agentProvider.InstanceName}' ({agentProvider.UsedLLMProvider.ToName()}, confidence={agentProvider.UsedLLMProvider.GetConfidence(this.SettingsManager).Level.GetName()}).");
|
||||||
this.ProviderSettings = agentProvider;
|
this.ProviderSettings = agentProvider;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
using AIStudio.Components;
|
using AIStudio.Components;
|
||||||
|
using AIStudio.Provider;
|
||||||
using AIStudio.Settings;
|
using AIStudio.Settings;
|
||||||
using AIStudio.Settings.DataModel;
|
using AIStudio.Settings.DataModel;
|
||||||
using AIStudio.Tools.ERIClient.DataModel;
|
using AIStudio.Tools.ERIClient.DataModel;
|
||||||
@ -76,6 +77,11 @@ public sealed record ChatThread
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public DataSourceSecurity DataSecurity { get; set; } = DataSourceSecurity.NOT_SPECIFIED;
|
public DataSourceSecurity DataSecurity { get; set; } = DataSourceSecurity.NOT_SPECIFIED;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The minimum provider confidence required by data sources used so far.
|
||||||
|
/// </summary>
|
||||||
|
public ConfidenceLevel DataComplianceLevel { get; set; } = ConfidenceLevel.NONE;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of the chat thread. Usually generated by an AI model or manually edited by the user.
|
/// The name of the chat thread. Usually generated by an AI model or manually edited by the user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -11,12 +11,12 @@ public static class ChatThreadExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// We don't check if the provider is allowed to use the data sources of the chat thread.
|
/// We don't check if the provider is allowed to use the data sources of the chat thread.
|
||||||
/// That kind of check is done in the RAG process itself.<br/><br/>
|
/// That kind of check is done when the available data sources are resolved.<br/><br/>
|
||||||
///
|
///
|
||||||
/// One thing which is not so obvious: after RAG was used on this thread, the entire chat
|
/// One thing which is not so obvious: after RAG was used on this thread, the entire chat
|
||||||
/// thread is kind of a data source by itself. Why? Because the augmentation data collected
|
/// thread is kind of a data source by itself. Why? Because the augmentation data collected
|
||||||
/// from the data sources is stored in the chat thread. This means we must check if the
|
/// from the data sources is stored in the chat thread. This means we must check if the
|
||||||
/// selected provider is allowed to use this thread's data.
|
/// selected provider is allowed to use this thread's data security and compliance level.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="chatThread">The chat thread to check.</param>
|
/// <param name="chatThread">The chat thread to check.</param>
|
||||||
/// <param name="provider">The provider to check.</param>
|
/// <param name="provider">The provider to check.</param>
|
||||||
@ -26,7 +26,19 @@ public static class ChatThreadExtensions
|
|||||||
// No chat thread available means we have a new chat. That's fine:
|
// No chat thread available means we have a new chat. That's fine:
|
||||||
if (chatThread is null)
|
if (chatThread is null)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
var settingsManager = Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||||
|
var providerConfidenceLevel = provider switch
|
||||||
|
{
|
||||||
|
IProvider p => p.GetConfidenceLevel(settingsManager),
|
||||||
|
AIStudio.Settings.Provider p => p.GetConfidenceLevel(settingsManager),
|
||||||
|
|
||||||
|
_ => ConfidenceLevel.NONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!providerConfidenceLevel.AllowsDataSourceComplianceLevel(chatThread.DataComplianceLevel))
|
||||||
|
return false;
|
||||||
|
|
||||||
// The chat thread is available, but the data security is not specified.
|
// The chat thread is available, but the data security is not specified.
|
||||||
// Means, we never used RAG or RAG was enabled, but no data sources were selected.
|
// Means, we never used RAG or RAG was enabled, but no data sources were selected.
|
||||||
// That's fine as well:
|
// That's fine as well:
|
||||||
@ -36,7 +48,6 @@ public static class ChatThreadExtensions
|
|||||||
//
|
//
|
||||||
// Is the provider trusted for data-source security checks?
|
// Is the provider trusted for data-source security checks?
|
||||||
//
|
//
|
||||||
var settingsManager = Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
|
||||||
var isTrustedProvider = provider switch
|
var isTrustedProvider = provider switch
|
||||||
{
|
{
|
||||||
IProvider p => p.IsTrustedForDataSourceSecurityChecks(settingsManager),
|
IProvider p => p.IsTrustedForDataSourceSecurityChecks(settingsManager),
|
||||||
|
|||||||
@ -57,7 +57,7 @@ public sealed class ContentText : IContent
|
|||||||
|
|
||||||
if(!chatThread.IsLLMProviderAllowed(provider))
|
if(!chatThread.IsLLMProviderAllowed(provider))
|
||||||
{
|
{
|
||||||
LOGGER.LogError("The provider is not allowed for this chat thread due to data security reasons. Skipping the AI process.");
|
LOGGER.LogError("The provider is not allowed for this chat thread due to data security or compliance reasons. Skipping the AI process.");
|
||||||
await this.CompleteWithoutStreaming();
|
await this.CompleteWithoutStreaming();
|
||||||
return chatThread;
|
return chatThread;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -147,7 +147,7 @@
|
|||||||
|
|
||||||
@if (!this.ChatThread.IsLLMProviderAllowed(this.Provider))
|
@if (!this.ChatThread.IsLLMProviderAllowed(this.Provider))
|
||||||
{
|
{
|
||||||
<MudTooltip Text="@T("The selected provider is not allowed in this chat due to data security reasons.")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
<MudTooltip Text="@T("The selected provider is not allowed in this chat due to data security or compliance reasons.")" Placement="@TOOLBAR_TOOLTIP_PLACEMENT">
|
||||||
<MudIconButton Icon="@Icons.Material.Filled.Error" Color="Color.Error"/>
|
<MudIconButton Icon="@Icons.Material.Filled.Error" Color="Color.Error"/>
|
||||||
</MudTooltip>
|
</MudTooltip>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -70,7 +70,7 @@
|
|||||||
{
|
{
|
||||||
case true when this.availableDataSources.Count == 0:
|
case true when this.availableDataSources.Count == 0:
|
||||||
<MudText Typo="Typo.body1" Class="mb-3">
|
<MudText Typo="Typo.body1" Class="mb-3">
|
||||||
@T("Your data sources cannot be used with the LLM provider you selected due to data privacy, or they are currently unavailable.")
|
@T("Your data sources cannot be used with the LLM provider you selected due to data privacy or compliance requirements, or they are currently unavailable.")
|
||||||
</MudText>
|
</MudText>
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -82,7 +82,7 @@
|
|||||||
|
|
||||||
case false when this.availableDataSources.Count == 0:
|
case false when this.availableDataSources.Count == 0:
|
||||||
<MudText Typo="Typo.body1" Class="mb-3">
|
<MudText Typo="Typo.body1" Class="mb-3">
|
||||||
@T("Your data sources cannot be used with the LLM provider you selected due to data privacy, or they are currently unavailable.")
|
@T("Your data sources cannot be used with the LLM provider you selected due to data privacy or compliance requirements, or they are currently unavailable.")
|
||||||
</MudText>
|
</MudText>
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -177,4 +177,4 @@ else if (this.SelectionMode is DataSourceSelectionMode.CONFIGURATION_MODE)
|
|||||||
</MudField>
|
</MudField>
|
||||||
}
|
}
|
||||||
</MudPaper>
|
</MudPaper>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,7 +73,7 @@
|
|||||||
</MudJustifiedText>
|
</MudJustifiedText>
|
||||||
@if (this.CanChangeSourceAndEmbedding)
|
@if (this.CanChangeSourceAndEmbedding)
|
||||||
{
|
{
|
||||||
<MudSelect @bind-Value="@this.dataEmbeddingId" Label="@T("Embedding")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.dataSourceValidation.ValidateEmbeddingId">
|
<MudSelect @bind-Value="@this.dataEmbeddingId" Label="@T("Embedding")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.dataSourceValidation.ValidateEmbeddingProviderAccess">
|
||||||
@foreach (var embedding in this.AvailableEmbeddings)
|
@foreach (var embedding in this.AvailableEmbeddings)
|
||||||
{
|
{
|
||||||
<MudSelectItem Value="@embedding.Value">
|
<MudSelectItem Value="@embedding.Value">
|
||||||
@ -99,18 +99,6 @@
|
|||||||
|
|
||||||
@if (!string.IsNullOrWhiteSpace(this.dataEmbeddingId))
|
@if (!string.IsNullOrWhiteSpace(this.dataEmbeddingId))
|
||||||
{
|
{
|
||||||
<MudTextField
|
|
||||||
T="string"
|
|
||||||
Text="@this.SelectedEmbeddingTokenizerText"
|
|
||||||
Label="@T("Tokenizer")"
|
|
||||||
Class="mb-3"
|
|
||||||
ReadOnly="@true"
|
|
||||||
Variant="Variant.Outlined"
|
|
||||||
Adornment="Adornment.Start"
|
|
||||||
AdornmentIcon="@Icons.Material.Filled.DataObject"
|
|
||||||
AdornmentColor="Color.Info"
|
|
||||||
/>
|
|
||||||
|
|
||||||
if (this.SelectedCloudEmbedding)
|
if (this.SelectedCloudEmbedding)
|
||||||
{
|
{
|
||||||
<DataSourceCloudEmbeddingWarning DataSourceType="DataSourceType.LOCAL_DIRECTORY" SourcePath="@this.dataPath" @bind-UserAcknowledged="@this.dataUserAcknowledgedCloudEmbedding" Validation="@this.dataSourceValidation.ValidateUserAcknowledgedCloudEmbedding"/>
|
<DataSourceCloudEmbeddingWarning DataSourceType="DataSourceType.LOCAL_DIRECTORY" SourcePath="@this.dataPath" @bind-UserAcknowledged="@this.dataUserAcknowledgedCloudEmbedding" Validation="@this.dataSourceValidation.ValidateUserAcknowledgedCloudEmbedding"/>
|
||||||
@ -121,59 +109,11 @@
|
|||||||
@T("The embedding you selected runs locally or in your organization. Your data is not sent to the cloud.")
|
@T("The embedding you selected runs locally or in your organization. Your data is not sent to the cloud.")
|
||||||
</MudJustifiedText>
|
</MudJustifiedText>
|
||||||
}
|
}
|
||||||
|
|
||||||
<MudStack Class="mb-3">
|
|
||||||
<MudButton OnClick="@this.ToggleExpertSettings" Variant="Variant.Text" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Tune">
|
|
||||||
@(this.showExpertSettings ? T("Hide Expert Settings") : T("Show Expert Settings"))
|
|
||||||
</MudButton>
|
|
||||||
<MudDivider/>
|
|
||||||
<MudCollapse Expanded="@this.showExpertSettings" Class="@this.GetExpertStyles">
|
|
||||||
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
|
||||||
@T("Optional expert settings for how this data source is split before embedding.")
|
|
||||||
</MudJustifiedText>
|
|
||||||
<MudNumericField
|
|
||||||
T="int"
|
|
||||||
@bind-Value="@this.dataMaxChunkTokenLength"
|
|
||||||
Label="@T("Token limit")"
|
|
||||||
Class="mb-3"
|
|
||||||
Min="0"
|
|
||||||
Immediate="@true"
|
|
||||||
Validation="@this.ValidateMaxChunkTokenLength"
|
|
||||||
HelperText="@T("Maximum number of tokens per chunk for this data source. Use 0 to use the embedding provider setting.")"
|
|
||||||
Variant="Variant.Outlined"
|
|
||||||
Adornment="Adornment.Start"
|
|
||||||
AdornmentIcon="@Icons.Material.Filled.DataObject"
|
|
||||||
AdornmentColor="Color.Info"
|
|
||||||
/>
|
|
||||||
<MudNumericField
|
|
||||||
T="int"
|
|
||||||
@bind-Value="@this.dataChunkOverlapTokenLength"
|
|
||||||
Label="@T("Token overlap")"
|
|
||||||
Min="0"
|
|
||||||
Immediate="@true"
|
|
||||||
Validation="@this.ValidateChunkOverlapTokenLength"
|
|
||||||
HelperText="@T("Number of tokens repeated at the start of the next chunk. Use 0 to use the default overlap.")"
|
|
||||||
Variant="Variant.Outlined"
|
|
||||||
Adornment="Adornment.Start"
|
|
||||||
AdornmentIcon="@Icons.Material.Filled.CompareArrows"
|
|
||||||
AdornmentColor="Color.Info"
|
|
||||||
/>
|
|
||||||
</MudCollapse>
|
|
||||||
</MudStack>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<ManagePandocDependency IntroText="@T("For some data types, such as Office files, MindWork AI Studio requires the open-source application Pandoc.")"/>
|
<ManagePandocDependency IntroText="@T("For some data types, such as Office files, MindWork AI Studio requires the open-source application Pandoc.")"/>
|
||||||
|
|
||||||
<MudSelect @bind-Value="@this.dataSecurityPolicy" Text="@this.dataSecurityPolicy.ToSelectionText()" Label="@T("Your security policy")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.dataSourceValidation.ValidateSecurityPolicy">
|
<MudSelect @bind-Value="@this.dataComplianceLevel" Text="@this.dataComplianceLevel.GetName()" Label="@T("Compliance level")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.dataSourceValidation.ValidateDataSourceComplianceLevel">
|
||||||
@foreach (var policy in Enum.GetValues<DataSourceSecurity>())
|
|
||||||
{
|
|
||||||
<MudSelectItem Value="@policy">
|
|
||||||
@policy.ToSelectionText()
|
|
||||||
</MudSelectItem>
|
|
||||||
}
|
|
||||||
</MudSelect>
|
|
||||||
|
|
||||||
<MudSelect @bind-Value="@this.dataComplianceLevel" Text="@this.dataComplianceLevel.GetName()" Label="@T("Compliance level")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start">
|
|
||||||
@foreach (var level in this.ComplianceLevels)
|
@foreach (var level in this.ComplianceLevels)
|
||||||
{
|
{
|
||||||
<MudSelectItem Value="@level.Value">
|
<MudSelectItem Value="@level.Value">
|
||||||
@ -182,7 +122,56 @@
|
|||||||
}
|
}
|
||||||
</MudSelect>
|
</MudSelect>
|
||||||
|
|
||||||
<MudNumericField T="ushort" Min="10" @bind-Value="@this.dataMaxMatches" Label="@T("How many matches do you want at most per query?")" Variant="Variant.Outlined" Step="10" />
|
<MudStack Class="mb-3">
|
||||||
|
<MudButton OnClick="@this.ToggleExpertSettings" Variant="Variant.Text" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Tune">
|
||||||
|
@(this.showExpertSettings ? T("Hide Expert Settings") : T("Show Expert Settings"))
|
||||||
|
</MudButton>
|
||||||
|
<MudDivider/>
|
||||||
|
<MudCollapse Expanded="@this.showExpertSettings" Class="@this.GetExpertStyles">
|
||||||
|
@if (!string.IsNullOrWhiteSpace(this.dataEmbeddingId))
|
||||||
|
{
|
||||||
|
<MudTextField
|
||||||
|
T="string"
|
||||||
|
Text="@this.SelectedEmbeddingTokenizerText"
|
||||||
|
Label="@T("Tokenizer")"
|
||||||
|
Class="mb-3"
|
||||||
|
ReadOnly="@true"
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
Adornment="Adornment.Start"
|
||||||
|
AdornmentIcon="@Icons.Material.Filled.DataObject"
|
||||||
|
AdornmentColor="Color.Info"/>
|
||||||
|
}
|
||||||
|
<MudJustifiedText Typo="Typo.body1" Class="mb-3">
|
||||||
|
@T("Optional expert settings for how this data source is split before embedding.")
|
||||||
|
</MudJustifiedText>
|
||||||
|
<MudNumericField
|
||||||
|
T="int"
|
||||||
|
@bind-Value="@this.dataMaxChunkTokenLength"
|
||||||
|
Label="@T("Token limit")"
|
||||||
|
Class="mb-3"
|
||||||
|
Min="0"
|
||||||
|
Immediate="@true"
|
||||||
|
Validation="@this.ValidateMaxChunkTokenLength"
|
||||||
|
HelperText="@T("Maximum number of tokens per chunk for this data source. Use 0 to use the embedding provider setting.")"
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
Adornment="Adornment.Start"
|
||||||
|
AdornmentIcon="@Icons.Material.Filled.DataObject"
|
||||||
|
AdornmentColor="Color.Info"/>
|
||||||
|
<MudNumericField
|
||||||
|
T="int"
|
||||||
|
@bind-Value="@this.dataChunkOverlapTokenLength"
|
||||||
|
Label="@T("Token overlap")"
|
||||||
|
Min="0"
|
||||||
|
Immediate="@true"
|
||||||
|
Validation="@this.ValidateChunkOverlapTokenLength"
|
||||||
|
HelperText="@T("Number of tokens repeated at the start of the next chunk. Use 0 to use the default overlap.")"
|
||||||
|
Variant="Variant.Outlined"
|
||||||
|
Adornment="Adornment.Start"
|
||||||
|
AdornmentIcon="@Icons.Material.Filled.CompareArrows"
|
||||||
|
AdornmentColor="Color.Info"/>
|
||||||
|
<MudNumericField T="ushort" Min="10" @bind-Value="@this.dataMaxMatches" Label="@T("How many matches do you want at most per query?")" Variant="Variant.Outlined" Step="10" />
|
||||||
|
</MudCollapse>
|
||||||
|
</MudStack>
|
||||||
</MudForm>
|
</MudForm>
|
||||||
<Issues IssuesData="@this.dataIssues"/>
|
<Issues IssuesData="@this.dataIssues"/>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|||||||
@ -49,7 +49,6 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
|||||||
private int dataChunkOverlapTokenLength;
|
private int dataChunkOverlapTokenLength;
|
||||||
private ushort dataMaxMatches = 10;
|
private ushort dataMaxMatches = 10;
|
||||||
private bool showExpertSettings;
|
private bool showExpertSettings;
|
||||||
private DataSourceSecurity dataSecurityPolicy;
|
|
||||||
private ConfidenceLevel dataComplianceLevel = ConfidenceLevel.UNKNOWN;
|
private ConfidenceLevel dataComplianceLevel = ConfidenceLevel.UNKNOWN;
|
||||||
|
|
||||||
// We get the form reference from Blazor code to validate it manually:
|
// We get the form reference from Blazor code to validate it manually:
|
||||||
@ -60,6 +59,10 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
|||||||
this.dataSourceValidation = new()
|
this.dataSourceValidation = new()
|
||||||
{
|
{
|
||||||
GetSelectedCloudEmbedding = () => this.SelectedCloudEmbedding,
|
GetSelectedCloudEmbedding = () => this.SelectedCloudEmbedding,
|
||||||
|
GetSelectedEmbeddingProvider = () => this.SelectedEmbedding,
|
||||||
|
GetSecurityPolicy = () => DataSourceSecurity.ALLOW_ANY,
|
||||||
|
GetComplianceLevel = () => this.dataComplianceLevel,
|
||||||
|
GetSettingsManager = () => this.SettingsManager,
|
||||||
GetPreviousDataSourceName = () => this.dataEditingPreviousInstanceName,
|
GetPreviousDataSourceName = () => this.dataEditingPreviousInstanceName,
|
||||||
GetUsedDataSourceNames = () => this.UsedDataSourcesNames,
|
GetUsedDataSourceNames = () => this.UsedDataSourcesNames,
|
||||||
};
|
};
|
||||||
@ -87,7 +90,6 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
|||||||
this.dataPath = this.DataSource.Path;
|
this.dataPath = this.DataSource.Path;
|
||||||
this.dataMaxChunkTokenLength = this.DataSource.MaxChunkTokenLength;
|
this.dataMaxChunkTokenLength = this.DataSource.MaxChunkTokenLength;
|
||||||
this.dataChunkOverlapTokenLength = this.DataSource.ChunkOverlapTokenLength;
|
this.dataChunkOverlapTokenLength = this.DataSource.ChunkOverlapTokenLength;
|
||||||
this.dataSecurityPolicy = this.DataSource.SecurityPolicy;
|
|
||||||
this.dataComplianceLevel = this.DataSource.ComplianceLevel;
|
this.dataComplianceLevel = this.DataSource.ComplianceLevel;
|
||||||
this.dataMaxMatches = this.DataSource.MaxMatches;
|
this.dataMaxMatches = this.DataSource.MaxMatches;
|
||||||
this.showExpertSettings = this.dataMaxChunkTokenLength > 0 || this.dataChunkOverlapTokenLength > 0;
|
this.showExpertSettings = this.dataMaxChunkTokenLength > 0 || this.dataChunkOverlapTokenLength > 0;
|
||||||
@ -143,7 +145,7 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
|||||||
Path = this.CanChangeSourceAndEmbedding ? this.dataPath : this.DataSource.Path,
|
Path = this.CanChangeSourceAndEmbedding ? this.dataPath : this.DataSource.Path,
|
||||||
MaxChunkTokenLength = this.dataMaxChunkTokenLength,
|
MaxChunkTokenLength = this.dataMaxChunkTokenLength,
|
||||||
ChunkOverlapTokenLength = this.dataChunkOverlapTokenLength,
|
ChunkOverlapTokenLength = this.dataChunkOverlapTokenLength,
|
||||||
SecurityPolicy = this.dataSecurityPolicy,
|
SecurityPolicy = DataSourceSecurity.ALLOW_ANY,
|
||||||
ComplianceLevel = this.dataComplianceLevel,
|
ComplianceLevel = this.dataComplianceLevel,
|
||||||
MaxMatches = this.dataMaxMatches,
|
MaxMatches = this.dataMaxMatches,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -38,7 +38,6 @@
|
|||||||
</MudJustifiedText>
|
</MudJustifiedText>
|
||||||
}
|
}
|
||||||
|
|
||||||
<TextInfoLines Label="@T("Your security policy")" MaxLines="3" Value="@this.DataSource.SecurityPolicy.ToInfoText()" Color="@this.DataSource.SecurityPolicy.GetColor()" ClipboardTooltipSubject="@T("your security policy")"/>
|
|
||||||
<TextInfoLine Label="@T("Compliance level")" Value="@this.DataSource.ComplianceLevel.GetName()" ClipboardTooltipSubject="@T("the compliance level")"/>
|
<TextInfoLine Label="@T("Compliance level")" Value="@this.DataSource.ComplianceLevel.GetName()" ClipboardTooltipSubject="@T("the compliance level")"/>
|
||||||
<TextInfoLine Label="@T("Maximum matches per query")" Value="@this.DataSource.MaxMatches.ToString()" ClipboardTooltipSubject="@T("the maximum number of matches per query")"/>
|
<TextInfoLine Label="@T("Maximum matches per query")" Value="@this.DataSource.MaxMatches.ToString()" ClipboardTooltipSubject="@T("the maximum number of matches per query")"/>
|
||||||
|
|
||||||
|
|||||||
@ -73,7 +73,7 @@
|
|||||||
</MudJustifiedText>
|
</MudJustifiedText>
|
||||||
@if (this.CanChangeSourceAndEmbedding)
|
@if (this.CanChangeSourceAndEmbedding)
|
||||||
{
|
{
|
||||||
<MudSelect @bind-Value="@this.dataEmbeddingId" Label="@T("Embedding")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.dataSourceValidation.ValidateEmbeddingId">
|
<MudSelect @bind-Value="@this.dataEmbeddingId" Label="@T("Embedding")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.dataSourceValidation.ValidateEmbeddingProviderAccess">
|
||||||
@foreach (var embedding in this.AvailableEmbeddings)
|
@foreach (var embedding in this.AvailableEmbeddings)
|
||||||
{
|
{
|
||||||
<MudSelectItem Value="@embedding.Value">
|
<MudSelectItem Value="@embedding.Value">
|
||||||
@ -164,16 +164,7 @@
|
|||||||
|
|
||||||
<ManagePandocDependency IntroText="@T("For some data types, such as Office files, MindWork AI Studio requires the open-source application Pandoc.")"/>
|
<ManagePandocDependency IntroText="@T("For some data types, such as Office files, MindWork AI Studio requires the open-source application Pandoc.")"/>
|
||||||
|
|
||||||
<MudSelect @bind-Value="@this.dataSecurityPolicy" Text="@this.dataSecurityPolicy.ToSelectionText()" Label="@T("Your security policy")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.dataSourceValidation.ValidateSecurityPolicy">
|
<MudSelect @bind-Value="@this.dataComplianceLevel" Text="@this.dataComplianceLevel.GetName()" Label="@T("Compliance level")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start" Validation="@this.dataSourceValidation.ValidateDataSourceComplianceLevel">
|
||||||
@foreach (var policy in Enum.GetValues<DataSourceSecurity>())
|
|
||||||
{
|
|
||||||
<MudSelectItem Value="@policy">
|
|
||||||
@policy.ToSelectionText()
|
|
||||||
</MudSelectItem>
|
|
||||||
}
|
|
||||||
</MudSelect>
|
|
||||||
|
|
||||||
<MudSelect @bind-Value="@this.dataComplianceLevel" Text="@this.dataComplianceLevel.GetName()" Label="@T("Compliance level")" Class="mb-3" OpenIcon="@Icons.Material.Filled.ExpandMore" AdornmentColor="Color.Info" Adornment="Adornment.Start">
|
|
||||||
@foreach (var level in this.ComplianceLevels)
|
@foreach (var level in this.ComplianceLevels)
|
||||||
{
|
{
|
||||||
<MudSelectItem Value="@level.Value">
|
<MudSelectItem Value="@level.Value">
|
||||||
|
|||||||
@ -49,7 +49,6 @@ public partial class DataSourceLocalFileDialog : MSGComponentBase
|
|||||||
private int dataChunkOverlapTokenLength;
|
private int dataChunkOverlapTokenLength;
|
||||||
private ushort dataMaxMatches = 10;
|
private ushort dataMaxMatches = 10;
|
||||||
private bool showExpertSettings;
|
private bool showExpertSettings;
|
||||||
private DataSourceSecurity dataSecurityPolicy;
|
|
||||||
private ConfidenceLevel dataComplianceLevel = ConfidenceLevel.UNKNOWN;
|
private ConfidenceLevel dataComplianceLevel = ConfidenceLevel.UNKNOWN;
|
||||||
|
|
||||||
// We get the form reference from Blazor code to validate it manually:
|
// We get the form reference from Blazor code to validate it manually:
|
||||||
@ -60,6 +59,10 @@ public partial class DataSourceLocalFileDialog : MSGComponentBase
|
|||||||
this.dataSourceValidation = new()
|
this.dataSourceValidation = new()
|
||||||
{
|
{
|
||||||
GetSelectedCloudEmbedding = () => this.SelectedCloudEmbedding,
|
GetSelectedCloudEmbedding = () => this.SelectedCloudEmbedding,
|
||||||
|
GetSelectedEmbeddingProvider = () => this.SelectedEmbedding,
|
||||||
|
GetSecurityPolicy = () => DataSourceSecurity.ALLOW_ANY,
|
||||||
|
GetComplianceLevel = () => this.dataComplianceLevel,
|
||||||
|
GetSettingsManager = () => this.SettingsManager,
|
||||||
GetPreviousDataSourceName = () => this.dataEditingPreviousInstanceName,
|
GetPreviousDataSourceName = () => this.dataEditingPreviousInstanceName,
|
||||||
GetUsedDataSourceNames = () => this.UsedDataSourcesNames,
|
GetUsedDataSourceNames = () => this.UsedDataSourcesNames,
|
||||||
};
|
};
|
||||||
@ -87,7 +90,6 @@ public partial class DataSourceLocalFileDialog : MSGComponentBase
|
|||||||
this.dataFilePath = this.DataSource.FilePath;
|
this.dataFilePath = this.DataSource.FilePath;
|
||||||
this.dataMaxChunkTokenLength = this.DataSource.MaxChunkTokenLength;
|
this.dataMaxChunkTokenLength = this.DataSource.MaxChunkTokenLength;
|
||||||
this.dataChunkOverlapTokenLength = this.DataSource.ChunkOverlapTokenLength;
|
this.dataChunkOverlapTokenLength = this.DataSource.ChunkOverlapTokenLength;
|
||||||
this.dataSecurityPolicy = this.DataSource.SecurityPolicy;
|
|
||||||
this.dataComplianceLevel = this.DataSource.ComplianceLevel;
|
this.dataComplianceLevel = this.DataSource.ComplianceLevel;
|
||||||
this.dataMaxMatches = this.DataSource.MaxMatches;
|
this.dataMaxMatches = this.DataSource.MaxMatches;
|
||||||
this.showExpertSettings = this.dataMaxChunkTokenLength > 0 || this.dataChunkOverlapTokenLength > 0;
|
this.showExpertSettings = this.dataMaxChunkTokenLength > 0 || this.dataChunkOverlapTokenLength > 0;
|
||||||
@ -143,7 +145,7 @@ public partial class DataSourceLocalFileDialog : MSGComponentBase
|
|||||||
FilePath = this.CanChangeSourceAndEmbedding ? this.dataFilePath : this.DataSource.FilePath,
|
FilePath = this.CanChangeSourceAndEmbedding ? this.dataFilePath : this.DataSource.FilePath,
|
||||||
MaxChunkTokenLength = this.dataMaxChunkTokenLength,
|
MaxChunkTokenLength = this.dataMaxChunkTokenLength,
|
||||||
ChunkOverlapTokenLength = this.dataChunkOverlapTokenLength,
|
ChunkOverlapTokenLength = this.dataChunkOverlapTokenLength,
|
||||||
SecurityPolicy = this.dataSecurityPolicy,
|
SecurityPolicy = DataSourceSecurity.ALLOW_ANY,
|
||||||
ComplianceLevel = this.dataComplianceLevel,
|
ComplianceLevel = this.dataComplianceLevel,
|
||||||
MaxMatches = this.dataMaxMatches,
|
MaxMatches = this.dataMaxMatches,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -38,7 +38,6 @@
|
|||||||
</MudJustifiedText>
|
</MudJustifiedText>
|
||||||
}
|
}
|
||||||
|
|
||||||
<TextInfoLines Label="@T("Your security policy")" MaxLines="3" Value="@this.DataSource.SecurityPolicy.ToInfoText()" Color="@this.DataSource.SecurityPolicy.GetColor()" ClipboardTooltipSubject="@T("your security policy")"/>
|
|
||||||
<TextInfoLine Label="@T("Compliance level")" Value="@this.DataSource.ComplianceLevel.GetName()" ClipboardTooltipSubject="@T("the compliance level")"/>
|
<TextInfoLine Label="@T("Compliance level")" Value="@this.DataSource.ComplianceLevel.GetName()" ClipboardTooltipSubject="@T("the compliance level")"/>
|
||||||
<TextInfoLine Label="@T("Maximum matches per query")" Value="@this.DataSource.MaxMatches.ToString()" ClipboardTooltipSubject="@T("the maximum number of matches per query")"/>
|
<TextInfoLine Label="@T("Maximum matches per query")" Value="@this.DataSource.MaxMatches.ToString()" ClipboardTooltipSubject="@T("the maximum number of matches per query")"/>
|
||||||
<TextInfoLine Icon="@Icons.Material.Filled.SquareFoot" Label="@T("File size")" Value="@this.FileSize" ClipboardTooltipSubject="@T("the file size")"/>
|
<TextInfoLine Icon="@Icons.Material.Filled.SquareFoot" Label="@T("File size")" Value="@this.FileSize" ClipboardTooltipSubject="@T("the file size")"/>
|
||||||
|
|||||||
@ -42,7 +42,7 @@ public readonly record struct DataSourceLocalDirectory : IInternalDataSource
|
|||||||
public int ChunkOverlapTokenLength { get; init; }
|
public int ChunkOverlapTokenLength { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public DataSourceSecurity SecurityPolicy { get; init; } = DataSourceSecurity.NOT_SPECIFIED;
|
public DataSourceSecurity SecurityPolicy { get; init; } = DataSourceSecurity.ALLOW_ANY;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ConfidenceLevel ComplianceLevel { get; init; } = ConfidenceLevel.UNKNOWN;
|
public ConfidenceLevel ComplianceLevel { get; init; } = ConfidenceLevel.UNKNOWN;
|
||||||
|
|||||||
@ -42,7 +42,7 @@ public readonly record struct DataSourceLocalFile : IInternalDataSource
|
|||||||
public int ChunkOverlapTokenLength { get; init; }
|
public int ChunkOverlapTokenLength { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public DataSourceSecurity SecurityPolicy { get; init; } = DataSourceSecurity.NOT_SPECIFIED;
|
public DataSourceSecurity SecurityPolicy { get; init; } = DataSourceSecurity.ALLOW_ANY;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ConfidenceLevel ComplianceLevel { get; init; } = ConfidenceLevel.UNKNOWN;
|
public ConfidenceLevel ComplianceLevel { get; init; } = ConfidenceLevel.UNKNOWN;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using AIStudio.Provider;
|
using AIStudio.Provider;
|
||||||
|
using AIStudio.Settings.DataModel;
|
||||||
|
|
||||||
namespace AIStudio.Settings;
|
namespace AIStudio.Settings;
|
||||||
|
|
||||||
@ -36,6 +37,97 @@ public static class DataSourceSecurityTrustExtensions
|
|||||||
return provider.Provider is LLMProviders.SELF_HOSTED || IsTrustedProviderId(provider.ConfiguredProviderId, settingsManager);
|
return provider.Provider is LLMProviders.SELF_HOSTED || IsTrustedProviderId(provider.ConfiguredProviderId, settingsManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ConfidenceLevel GetConfidenceLevel(this Provider provider, SettingsManager settingsManager)
|
||||||
|
{
|
||||||
|
if (provider == Provider.NONE)
|
||||||
|
return ConfidenceLevel.NONE;
|
||||||
|
|
||||||
|
return provider.UsedLLMProvider.GetConfidence(settingsManager).Level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConfidenceLevel GetConfidenceLevel(this EmbeddingProvider provider, SettingsManager settingsManager)
|
||||||
|
{
|
||||||
|
if (provider == EmbeddingProvider.NONE)
|
||||||
|
return ConfidenceLevel.NONE;
|
||||||
|
|
||||||
|
return provider.UsedLLMProvider.GetConfidence(settingsManager).Level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConfidenceLevel GetConfidenceLevel(this IProvider provider, SettingsManager settingsManager)
|
||||||
|
{
|
||||||
|
if (provider is NoProvider)
|
||||||
|
return ConfidenceLevel.NONE;
|
||||||
|
|
||||||
|
return provider.Provider.GetConfidence(settingsManager).Level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool AllowsDataSourceAccess(this Provider provider, SettingsManager settingsManager, DataSourceSecurity dataSourceSecurity, ConfidenceLevel dataSourceComplianceLevel)
|
||||||
|
{
|
||||||
|
return provider.AllowsDataSourceSecurity(dataSourceSecurity, settingsManager)
|
||||||
|
&& provider.GetConfidenceLevel(settingsManager).AllowsDataSourceComplianceLevel(dataSourceComplianceLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool AllowsDataSourceAccess(this EmbeddingProvider provider, SettingsManager settingsManager, DataSourceSecurity dataSourceSecurity, ConfidenceLevel dataSourceComplianceLevel)
|
||||||
|
{
|
||||||
|
return provider.AllowsDataSourceSecurity(dataSourceSecurity, settingsManager)
|
||||||
|
&& provider.GetConfidenceLevel(settingsManager).AllowsDataSourceComplianceLevel(dataSourceComplianceLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool AllowsDataSourceAccess(this IProvider provider, SettingsManager settingsManager, DataSourceSecurity dataSourceSecurity, ConfidenceLevel dataSourceComplianceLevel)
|
||||||
|
{
|
||||||
|
return provider.AllowsDataSourceSecurity(dataSourceSecurity, settingsManager)
|
||||||
|
&& provider.GetConfidenceLevel(settingsManager).AllowsDataSourceComplianceLevel(dataSourceComplianceLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool AllowsDataSourceSecurity(this Provider provider, DataSourceSecurity dataSourceSecurity, SettingsManager settingsManager)
|
||||||
|
=> provider.IsTrustedForDataSourceSecurityChecks(settingsManager).AllowsDataSourceSecurity(dataSourceSecurity);
|
||||||
|
|
||||||
|
public static bool AllowsDataSourceSecurity(this EmbeddingProvider provider, DataSourceSecurity dataSourceSecurity, SettingsManager settingsManager)
|
||||||
|
=> provider.IsTrustedForDataSourceSecurityChecks(settingsManager).AllowsDataSourceSecurity(dataSourceSecurity);
|
||||||
|
|
||||||
|
public static bool AllowsDataSourceSecurity(this IProvider provider, DataSourceSecurity dataSourceSecurity, SettingsManager settingsManager)
|
||||||
|
=> provider.IsTrustedForDataSourceSecurityChecks(settingsManager).AllowsDataSourceSecurity(dataSourceSecurity);
|
||||||
|
|
||||||
|
public static bool AllowsDataSourceSecurity(this bool usingTrustedProvider, DataSourceSecurity dataSourceSecurity) => dataSourceSecurity switch
|
||||||
|
{
|
||||||
|
DataSourceSecurity.ALLOW_ANY => true,
|
||||||
|
DataSourceSecurity.SELF_HOSTED => usingTrustedProvider,
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
public static bool AllowsDataSourceComplianceLevel(this ConfidenceLevel providerConfidenceLevel, ConfidenceLevel dataSourceComplianceLevel)
|
||||||
|
{
|
||||||
|
if (dataSourceComplianceLevel is ConfidenceLevel.NONE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return providerConfidenceLevel >= dataSourceComplianceLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConfidenceLevel GetRequiredComplianceLevel(this IEnumerable<IDataSource> dataSources)
|
||||||
|
{
|
||||||
|
var requiredComplianceLevel = ConfidenceLevel.NONE;
|
||||||
|
foreach (var dataSource in dataSources)
|
||||||
|
if (dataSource.ComplianceLevel > requiredComplianceLevel)
|
||||||
|
requiredComplianceLevel = dataSource.ComplianceLevel;
|
||||||
|
|
||||||
|
return requiredComplianceLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataSourceSecurity GetRequiredSecurityPolicy(this IEnumerable<IDataSource> dataSources)
|
||||||
|
{
|
||||||
|
var requiredSecurityPolicy = DataSourceSecurity.ALLOW_ANY;
|
||||||
|
foreach (var dataSource in dataSources)
|
||||||
|
{
|
||||||
|
if (dataSource.SecurityPolicy is DataSourceSecurity.NOT_SPECIFIED)
|
||||||
|
return DataSourceSecurity.NOT_SPECIFIED;
|
||||||
|
|
||||||
|
if (dataSource.SecurityPolicy is DataSourceSecurity.SELF_HOSTED)
|
||||||
|
requiredSecurityPolicy = DataSourceSecurity.SELF_HOSTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return requiredSecurityPolicy;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsTrustedByConfiguration(this Provider provider, SettingsManager settingsManager) => IsTrustedProviderId(provider.Id, settingsManager);
|
public static bool IsTrustedByConfiguration(this Provider provider, SettingsManager settingsManager) => IsTrustedProviderId(provider.Id, settingsManager);
|
||||||
|
|
||||||
public static bool IsTrustedByConfiguration(this EmbeddingProvider provider, SettingsManager settingsManager) => IsTrustedProviderId(provider.Id, settingsManager);
|
public static bool IsTrustedByConfiguration(this EmbeddingProvider provider, SettingsManager settingsManager) => IsTrustedProviderId(provider.Id, settingsManager);
|
||||||
|
|||||||
@ -43,19 +43,22 @@ public sealed class AugmentationOne : IAugmentationProcess
|
|||||||
{
|
{
|
||||||
// Let's get the validation agent & set up its provider:
|
// Let's get the validation agent & set up its provider:
|
||||||
var validationAgent = Program.SERVICE_PROVIDER.GetService<AgentRetrievalContextValidation>()!;
|
var validationAgent = Program.SERVICE_PROVIDER.GetService<AgentRetrievalContextValidation>()!;
|
||||||
validationAgent.SetLLMProvider(provider);
|
if (validationAgent.SetLLMProvider(provider, chatThread.DataSecurity, chatThread.DataComplianceLevel))
|
||||||
|
{
|
||||||
|
// Let's validate all retrieval contexts:
|
||||||
|
var validationResults = await validationAgent.ValidateRetrievalContextsAsync(lastUserPrompt, chatThread, retrievalContexts, token);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Now, filter the retrieval contexts to the most relevant ones:
|
||||||
|
//
|
||||||
|
var targetWindow = validationResults.DetermineTargetWindow(TargetWindowStrategy.TOP10_BETTER_THAN_GUESSING);
|
||||||
|
var threshold = validationResults.GetConfidenceThreshold(targetWindow);
|
||||||
|
|
||||||
// Let's validate all retrieval contexts:
|
// Filter the retrieval contexts:
|
||||||
var validationResults = await validationAgent.ValidateRetrievalContextsAsync(lastUserPrompt, chatThread, retrievalContexts, token);
|
retrievalContexts = validationResults.Where(x => x.RetrievalContext is not null && x.Confidence >= threshold).Select(x => x.RetrievalContext!).ToList();
|
||||||
|
}
|
||||||
//
|
else
|
||||||
// Now, filter the retrieval contexts to the most relevant ones:
|
LOGGER.LogWarning("Skipping retrieval context validation because no compliant validation agent provider is available.");
|
||||||
//
|
|
||||||
var targetWindow = validationResults.DetermineTargetWindow(TargetWindowStrategy.TOP10_BETTER_THAN_GUESSING);
|
|
||||||
var threshold = validationResults.GetConfidenceThreshold(targetWindow);
|
|
||||||
|
|
||||||
// Filter the retrieval contexts:
|
|
||||||
retrievalContexts = validationResults.Where(x => x.RetrievalContext is not null && x.Confidence >= threshold).Select(x => x.RetrievalContext!).ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGGER.LogInformation($"Starting the augmentation process over {numTotalRetrievalContexts:###,###,###,###} retrieval contexts.");
|
LOGGER.LogInformation($"Starting the augmentation process over {numTotalRetrievalContexts:###,###,###,###} retrieval contexts.");
|
||||||
|
|||||||
@ -31,11 +31,9 @@ public class AgenticSrcSelWithDynHeur : IDataSourceSelectionProcess
|
|||||||
IReadOnlyList<IDataSource> selectedDataSources = [];
|
IReadOnlyList<IDataSource> selectedDataSources = [];
|
||||||
IReadOnlyList<DataSourceAgentSelected> finalAISelection = [];
|
IReadOnlyList<DataSourceAgentSelected> finalAISelection = [];
|
||||||
|
|
||||||
// Get the settings manager:
|
|
||||||
var settings = Program.SERVICE_PROVIDER.GetService<SettingsManager>()!;
|
|
||||||
|
|
||||||
// Get the agent for the data source selection:
|
// Get the agent for the data source selection:
|
||||||
var selectionAgent = Program.SERVICE_PROVIDER.GetService<AgentDataSourceSelection>()!;
|
var selectionAgent = Program.SERVICE_PROVIDER.GetService<AgentDataSourceSelection>()!;
|
||||||
|
var allowedDataSources = dataSources.AllowedDataSources.ToDictionary(ds => ds.Id, StringComparer.Ordinal);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -61,14 +59,14 @@ public class AgenticSrcSelWithDynHeur : IDataSourceSelectionProcess
|
|||||||
var totalAISelectedDataSources = aiSelectedDataSources.Count;
|
var totalAISelectedDataSources = aiSelectedDataSources.Count;
|
||||||
|
|
||||||
// Filter out the data sources that are not available:
|
// Filter out the data sources that are not available:
|
||||||
aiSelectedDataSources = aiSelectedDataSources.Where(x => settings.ConfigurationData.DataSources.FirstOrDefault(ds => ds.Id == x.Id) is not null).ToList();
|
aiSelectedDataSources = aiSelectedDataSources.Where(x => allowedDataSources.ContainsKey(x.Id)).ToList();
|
||||||
|
|
||||||
// Store the real AI-selected data sources:
|
// Store the real AI-selected data sources:
|
||||||
finalAISelection = aiSelectedDataSources.Select(x => new DataSourceAgentSelected { DataSource = settings.ConfigurationData.DataSources.First(ds => ds.Id == x.Id), AIDecision = x, Selected = false }).ToList();
|
finalAISelection = aiSelectedDataSources.Select(x => new DataSourceAgentSelected { DataSource = allowedDataSources[x.Id], AIDecision = x, Selected = false }).ToList();
|
||||||
|
|
||||||
var numHallucinatedSources = totalAISelectedDataSources - aiSelectedDataSources.Count;
|
var numHallucinatedSources = totalAISelectedDataSources - aiSelectedDataSources.Count;
|
||||||
if (numHallucinatedSources > 0)
|
if (numHallucinatedSources > 0)
|
||||||
LOGGER.LogWarning($"The AI hallucinated {numHallucinatedSources} data source(s). We ignore them.");
|
LOGGER.LogWarning($"The AI selected {numHallucinatedSources} unavailable data source(s). We ignore them.");
|
||||||
|
|
||||||
if (aiSelectedDataSources.Count > 3)
|
if (aiSelectedDataSources.Count > 3)
|
||||||
{
|
{
|
||||||
@ -87,7 +85,7 @@ public class AgenticSrcSelWithDynHeur : IDataSourceSelectionProcess
|
|||||||
LOGGER.LogInformation($"The AI selected {aiSelectedDataSources.Count} data source(s) with a confidence of at least {threshold}.");
|
LOGGER.LogInformation($"The AI selected {aiSelectedDataSources.Count} data source(s) with a confidence of at least {threshold}.");
|
||||||
|
|
||||||
// Transform the final data sources to the actual data sources:
|
// Transform the final data sources to the actual data sources:
|
||||||
selectedDataSources = aiSelectedDataSources.Select(x => settings.ConfigurationData.DataSources.FirstOrDefault(ds => ds.Id == x.Id)).Where(ds => ds is not null).ToList()!;
|
selectedDataSources = aiSelectedDataSources.Select(x => allowedDataSources[x.Id]).ToList();
|
||||||
return new(proceedWithRAG, selectedDataSources);
|
return new(proceedWithRAG, selectedDataSources);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +94,7 @@ public class AgenticSrcSelWithDynHeur : IDataSourceSelectionProcess
|
|||||||
//
|
//
|
||||||
|
|
||||||
// Transform the selected data sources to the actual data sources:
|
// Transform the selected data sources to the actual data sources:
|
||||||
selectedDataSources = aiSelectedDataSources.Select(x => settings.ConfigurationData.DataSources.FirstOrDefault(ds => ds.Id == x.Id)).Where(ds => ds is not null).ToList()!;
|
selectedDataSources = aiSelectedDataSources.Select(x => allowedDataSources[x.Id]).ToList();
|
||||||
|
|
||||||
// Mark the data sources as selected:
|
// Mark the data sources as selected:
|
||||||
foreach (var dataSource in finalAISelection)
|
foreach (var dataSource in finalAISelection)
|
||||||
|
|||||||
@ -92,7 +92,7 @@ public sealed class AISrcSelWithRetCtxVal : IRagProcess
|
|||||||
//
|
//
|
||||||
// No, the user made the choice manually:
|
// No, the user made the choice manually:
|
||||||
//
|
//
|
||||||
var selectedDataSourceInfo = selectedDataSources.Select(ds => ds.Name).Aggregate((a, b) => $"'{a}', '{b}'");
|
var selectedDataSourceInfo = string.Join(", ", selectedDataSources.Select(ds => $"'{ds.Name}'"));
|
||||||
LOGGER.LogInformation($"The user selected the data sources manually. {selectedDataSources.Count} data source(s) are selected: {selectedDataSourceInfo}.");
|
LOGGER.LogInformation($"The user selected the data sources manually. {selectedDataSources.Count} data source(s) are selected: {selectedDataSourceInfo}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,12 +104,13 @@ public sealed class AISrcSelWithRetCtxVal : IRagProcess
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var previousDataSecurity = chatThread.DataSecurity;
|
var previousDataSecurity = chatThread.DataSecurity;
|
||||||
|
var previousDataComplianceLevel = chatThread.DataComplianceLevel;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Update the data security of the chat thread. We consider the current data security
|
// Update the data security of the chat thread. We consider the current data security
|
||||||
// of the chat thread and the data security of the selected data sources:
|
// of the chat thread and the data security of the selected data sources:
|
||||||
//
|
//
|
||||||
var dataSecurityRestrictedToSelfHosted = selectedDataSources.Any(x => x.SecurityPolicy is DataSourceSecurity.SELF_HOSTED);
|
var dataSecurityRestrictedToSelfHosted = selectedDataSources.Any(x => x is not IInternalDataSource && x.SecurityPolicy is DataSourceSecurity.SELF_HOSTED);
|
||||||
chatThread.DataSecurity = dataSecurityRestrictedToSelfHosted switch
|
chatThread.DataSecurity = dataSecurityRestrictedToSelfHosted switch
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
@ -150,6 +151,13 @@ public sealed class AISrcSelWithRetCtxVal : IRagProcess
|
|||||||
|
|
||||||
if (previousDataSecurity != chatThread.DataSecurity)
|
if (previousDataSecurity != chatThread.DataSecurity)
|
||||||
LOGGER.LogInformation($"The data security of the chat thread was updated from '{previousDataSecurity}' to '{chatThread.DataSecurity}'.");
|
LOGGER.LogInformation($"The data security of the chat thread was updated from '{previousDataSecurity}' to '{chatThread.DataSecurity}'.");
|
||||||
|
|
||||||
|
foreach (var dataSource in selectedDataSources)
|
||||||
|
if (dataSource.ComplianceLevel > chatThread.DataComplianceLevel)
|
||||||
|
chatThread.DataComplianceLevel = dataSource.ComplianceLevel;
|
||||||
|
|
||||||
|
if (previousDataComplianceLevel != chatThread.DataComplianceLevel)
|
||||||
|
LOGGER.LogInformation($"The data compliance level of the chat thread was updated from '{previousDataComplianceLevel.GetName()}' to '{chatThread.DataComplianceLevel.GetName()}'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@ -434,7 +434,24 @@ public sealed partial class DataSourceEmbeddingService(SettingsManager settingsM
|
|||||||
this.UpsertStatus(this.GetFallbackStatus(dataSource, "The selected embedding provider is not available."));
|
this.UpsertStatus(this.GetFallbackStatus(dataSource, "The selected embedding provider is not available."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!embeddingProvider.AllowsDataSourceAccess(settingsManager, dataSource.SecurityPolicy, dataSource.ComplianceLevel))
|
||||||
|
{
|
||||||
|
var errorMessage = $"The selected embedding provider is not allowed to embed this data source. The data source requires provider confidence '{dataSource.ComplianceLevel.GetName()}'. The embedding provider has confidence '{embeddingProvider.GetConfidenceLevel(settingsManager).GetName()}'.";
|
||||||
|
logger.LogWarning(
|
||||||
|
"Skipping background embeddings for data source '{DataSourceName}' ({DataSourceId}) because embedding provider '{EmbeddingProviderName}' ({EmbeddingProviderId}) is not allowed. RequiredDataSecurity={RequiredDataSecurity}, RequiredCompliance={RequiredCompliance}, EmbeddingProviderConfidence={EmbeddingProviderConfidence}.",
|
||||||
|
dataSource.Name,
|
||||||
|
dataSource.Id,
|
||||||
|
embeddingProvider.Name,
|
||||||
|
embeddingProvider.Id,
|
||||||
|
dataSource.SecurityPolicy,
|
||||||
|
dataSource.ComplianceLevel.GetName(),
|
||||||
|
embeddingProvider.GetConfidenceLevel(settingsManager).GetName());
|
||||||
|
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
this.UpsertStatus(this.GetFallbackStatus(dataSource, errorMessage));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
logger.LogInformation(
|
logger.LogInformation(
|
||||||
"Using embedding provider '{EmbeddingProviderId}' with model '{EmbeddingModelId}' for data source '{DataSourceName}' ({DataSourceId}).",
|
"Using embedding provider '{EmbeddingProviderId}' with model '{EmbeddingModelId}' for data source '{DataSourceName}' ({DataSourceId}).",
|
||||||
|
|||||||
@ -42,7 +42,10 @@ public sealed class DataSourceService
|
|||||||
return new([], []);
|
return new([], []);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.GetDataSources(selectedLLMProvider.IsTrustedForDataSourceSecurityChecks(this.settingsManager), previousSelectedDataSources);
|
return await this.GetDataSources(
|
||||||
|
selectedLLMProvider.IsTrustedForDataSourceSecurityChecks(this.settingsManager),
|
||||||
|
selectedLLMProvider.GetConfidenceLevel(this.settingsManager),
|
||||||
|
previousSelectedDataSources);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -65,10 +68,13 @@ public sealed class DataSourceService
|
|||||||
return new([], []);
|
return new([], []);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await this.GetDataSources(selectedLLMProvider.IsTrustedForDataSourceSecurityChecks(this.settingsManager), previousSelectedDataSources);
|
return await this.GetDataSources(
|
||||||
|
selectedLLMProvider.IsTrustedForDataSourceSecurityChecks(this.settingsManager),
|
||||||
|
selectedLLMProvider.GetConfidenceLevel(this.settingsManager),
|
||||||
|
previousSelectedDataSources);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<AllowedSelectedDataSources> GetDataSources(bool usingTrustedProvider, IReadOnlyCollection<IDataSource>? previousSelectedDataSources = null)
|
private async Task<AllowedSelectedDataSources> GetDataSources(bool usingTrustedProvider, ConfidenceLevel providerConfidenceLevel, IReadOnlyCollection<IDataSource>? previousSelectedDataSources = null)
|
||||||
{
|
{
|
||||||
var allDataSources = this.settingsManager.ConfigurationData.DataSources.ToList();
|
var allDataSources = this.settingsManager.ConfigurationData.DataSources.ToList();
|
||||||
var previousSelectedDataSourceIds = previousSelectedDataSources?.Select(source => source.Id).ToHashSet(StringComparer.Ordinal) ?? [];
|
var previousSelectedDataSourceIds = previousSelectedDataSources?.Select(source => source.Id).ToHashSet(StringComparer.Ordinal) ?? [];
|
||||||
@ -78,7 +84,7 @@ public sealed class DataSourceService
|
|||||||
|
|
||||||
// Start all checks in parallel:
|
// Start all checks in parallel:
|
||||||
foreach (var source in allDataSources)
|
foreach (var source in allDataSources)
|
||||||
tasks.Add(this.CheckOneDataSource(source, usingTrustedProvider));
|
tasks.Add(this.CheckOneDataSource(source, usingTrustedProvider, providerConfidenceLevel));
|
||||||
|
|
||||||
// Wait for all checks and collect the results:
|
// Wait for all checks and collect the results:
|
||||||
foreach (var task in tasks)
|
foreach (var task in tasks)
|
||||||
@ -95,8 +101,17 @@ public sealed class DataSourceService
|
|||||||
return new(filteredDataSources, filteredSelectedDataSources);
|
return new(filteredDataSources, filteredSelectedDataSources);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IDataSource?> CheckOneDataSource(IDataSource source, bool usingTrustedProvider)
|
private async Task<IDataSource?> CheckOneDataSource(IDataSource source, bool usingTrustedProvider, ConfidenceLevel providerConfidenceLevel)
|
||||||
{
|
{
|
||||||
|
if (!providerConfidenceLevel.AllowsDataSourceComplianceLevel(source.ComplianceLevel))
|
||||||
|
{
|
||||||
|
this.logger.LogWarning($"The data source '{source.Name}' (id={source.Id}) requires provider confidence '{source.ComplianceLevel.GetName()}'. The selected provider only has confidence '{providerConfidenceLevel.GetName()}'. We skip this source.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source is IInternalDataSource)
|
||||||
|
return source;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Unfortunately, we have to live-check any ERI source for its security requirements.
|
// Unfortunately, we have to live-check any ERI source for its security requirements.
|
||||||
// Because the ERI server operator might change the security requirements at any time.
|
// Because the ERI server operator might change the security requirements at any time.
|
||||||
@ -206,4 +221,4 @@ public sealed class DataSourceService
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
using AIStudio.Provider;
|
||||||
|
using AIStudio.Settings;
|
||||||
using AIStudio.Settings.DataModel;
|
using AIStudio.Settings.DataModel;
|
||||||
using AIStudio.Tools.ERIClient.DataModel;
|
using AIStudio.Tools.ERIClient.DataModel;
|
||||||
using AIStudio.Tools.PluginSystem;
|
using AIStudio.Tools.PluginSystem;
|
||||||
@ -19,6 +21,14 @@ public sealed class DataSourceValidation
|
|||||||
public Func<SecurityRequirements?> GetSecurityRequirements { get; init; } = () => null;
|
public Func<SecurityRequirements?> GetSecurityRequirements { get; init; } = () => null;
|
||||||
|
|
||||||
public Func<bool> GetSelectedCloudEmbedding { get; init; } = () => false;
|
public Func<bool> GetSelectedCloudEmbedding { get; init; } = () => false;
|
||||||
|
|
||||||
|
public Func<EmbeddingProvider?> GetSelectedEmbeddingProvider { get; init; } = () => null;
|
||||||
|
|
||||||
|
public Func<DataSourceSecurity> GetSecurityPolicy { get; init; } = () => DataSourceSecurity.ALLOW_ANY;
|
||||||
|
|
||||||
|
public Func<ConfidenceLevel> GetComplianceLevel { get; init; } = () => ConfidenceLevel.NONE;
|
||||||
|
|
||||||
|
public Func<SettingsManager?> GetSettingsManager { get; init; } = () => null;
|
||||||
|
|
||||||
public Func<bool> GetTestedConnection { get; init; } = () => false;
|
public Func<bool> GetTestedConnection { get; init; } = () => false;
|
||||||
|
|
||||||
@ -149,6 +159,20 @@ public sealed class DataSourceValidation
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string? ValidateEmbeddingProviderAccess(string embeddingId)
|
||||||
|
{
|
||||||
|
var embeddingIssue = this.ValidateEmbeddingId(embeddingId);
|
||||||
|
return embeddingIssue ?? this.ValidateSelectedEmbeddingProviderAccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? ValidateDataSourceComplianceLevel(ConfidenceLevel complianceLevel)
|
||||||
|
{
|
||||||
|
if(complianceLevel is ConfidenceLevel.NONE)
|
||||||
|
return TB("Please select a compliance level.");
|
||||||
|
|
||||||
|
return this.ValidateSelectedEmbeddingProviderAccess();
|
||||||
|
}
|
||||||
|
|
||||||
public string? ValidateUserAcknowledgedCloudEmbedding(bool value)
|
public string? ValidateUserAcknowledgedCloudEmbedding(bool value)
|
||||||
{
|
{
|
||||||
if(this.GetSelectedCloudEmbedding() && !value)
|
if(this.GetSelectedCloudEmbedding() && !value)
|
||||||
@ -175,4 +199,25 @@ public sealed class DataSourceValidation
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private string? ValidateSelectedEmbeddingProviderAccess()
|
||||||
|
{
|
||||||
|
var selectedEmbedding = this.GetSelectedEmbeddingProvider();
|
||||||
|
var settingsManager = this.GetSettingsManager();
|
||||||
|
if(selectedEmbedding is null || settingsManager is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var dataSecurity = this.GetSecurityPolicy();
|
||||||
|
var complianceLevel = this.GetComplianceLevel();
|
||||||
|
if(selectedEmbedding.AllowsDataSourceAccess(settingsManager, dataSecurity, complianceLevel))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if(!selectedEmbedding.AllowsDataSourceSecurity(dataSecurity, settingsManager))
|
||||||
|
return TB("The selected embedding provider is not allowed to process this data source due to its data security policy. Select a self-hosted or organization-trusted embedding provider.");
|
||||||
|
|
||||||
|
return string.Format(
|
||||||
|
TB("The selected embedding provider has confidence '{0}', but this data source requires provider confidence '{1}'. Select an embedding provider with equal or higher confidence or lower the compliance level."),
|
||||||
|
selectedEmbedding.GetConfidenceLevel(settingsManager).GetName(),
|
||||||
|
complianceLevel.GetName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user