mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-06-27 14:56:27 +00:00
Added support for organization-trusted providers
This commit is contained in:
parent
e65110a142
commit
78670b310b
@ -1,4 +1,5 @@
|
||||
using AIStudio.Provider.SelfHosted;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Settings.DataModel;
|
||||
|
||||
namespace AIStudio.Chat;
|
||||
@ -33,12 +34,13 @@ public static class ChatThreadExtensions
|
||||
return true;
|
||||
|
||||
//
|
||||
// Is the provider self-hosted?
|
||||
// Is the provider trusted for data-source security checks?
|
||||
//
|
||||
var isSelfHostedProvider = provider switch
|
||||
var settingsManager = Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
var isTrustedProvider = provider switch
|
||||
{
|
||||
ProviderSelfHosted => true,
|
||||
AIStudio.Settings.Provider p => p.IsSelfHosted,
|
||||
IProvider p => p.IsTrustedForDataSourceSecurityChecks(settingsManager),
|
||||
AIStudio.Settings.Provider p => p.IsTrustedForDataSourceSecurityChecks(settingsManager),
|
||||
|
||||
_ => false,
|
||||
};
|
||||
@ -46,12 +48,12 @@ public static class ChatThreadExtensions
|
||||
//
|
||||
// Check the chat data security against the selected provider:
|
||||
//
|
||||
return isSelfHostedProvider switch
|
||||
return isTrustedProvider switch
|
||||
{
|
||||
// The provider is self-hosted -- we can use any data source:
|
||||
// The provider is trusted -- we can use any data source:
|
||||
true => true,
|
||||
|
||||
// The provider is not self-hosted -- it depends on the data security of the chat thread:
|
||||
// The provider is not trusted -- it depends on the data security of the chat thread:
|
||||
false => chatThread.DataSecurity is not DataSourceSecurity.SELF_HOSTED,
|
||||
};
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ public partial class DataSourceLocalDirectoryDialog : MSGComponentBase
|
||||
|
||||
#endregion
|
||||
|
||||
private bool SelectedCloudEmbedding => !this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.dataEmbeddingId)?.IsSelfHosted ?? false;
|
||||
private bool SelectedCloudEmbedding => !(this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.dataEmbeddingId)?.IsTrustedForDataSourceSecurityChecks(this.SettingsManager) ?? false);
|
||||
|
||||
private DataSourceLocalDirectory CreateDataSource() => new()
|
||||
{
|
||||
|
||||
@ -56,7 +56,7 @@ public partial class DataSourceLocalDirectoryInfoDialog : MSGComponentBase, IAsy
|
||||
|
||||
private bool IsOperationInProgress { get; set; } = true;
|
||||
|
||||
private bool IsCloudEmbedding => !this.embeddingProvider.IsSelfHosted;
|
||||
private bool IsCloudEmbedding => !this.embeddingProvider.IsTrustedForDataSourceSecurityChecks(this.SettingsManager);
|
||||
|
||||
private bool IsDirectoryAvailable => this.directoryInfo.Exists;
|
||||
|
||||
|
||||
@ -96,7 +96,7 @@ public partial class DataSourceLocalFileDialog : MSGComponentBase
|
||||
|
||||
#endregion
|
||||
|
||||
private bool SelectedCloudEmbedding => !this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.dataEmbeddingId)?.IsSelfHosted ?? false;
|
||||
private bool SelectedCloudEmbedding => !(this.SettingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(x => x.Id == this.dataEmbeddingId)?.IsTrustedForDataSourceSecurityChecks(this.SettingsManager) ?? false);
|
||||
|
||||
private DataSourceLocalFile CreateDataSource() => new()
|
||||
{
|
||||
|
||||
@ -28,7 +28,7 @@ public partial class DataSourceLocalFileInfoDialog : MSGComponentBase
|
||||
private EmbeddingProvider embeddingProvider = EmbeddingProvider.NONE;
|
||||
private FileInfo fileInfo = null!;
|
||||
|
||||
private bool IsCloudEmbedding => !this.embeddingProvider.IsSelfHosted;
|
||||
private bool IsCloudEmbedding => !this.embeddingProvider.IsTrustedForDataSourceSecurityChecks(this.SettingsManager);
|
||||
|
||||
private bool IsFileAvailable => this.fileInfo.Exists;
|
||||
|
||||
|
||||
@ -337,6 +337,15 @@ CONFIG["SETTINGS"] = {}
|
||||
--
|
||||
-- Configure whether users can change the custom confidence scheme locally.
|
||||
-- CONFIG["SETTINGS"]["DataConfidence.CustomConfidenceScheme.AllowUserOverride"] = false
|
||||
--
|
||||
-- Configure provider instances trusted by your organization for data-source security checks.
|
||||
-- These IDs may refer to LLM providers, embedding providers, or transcription providers
|
||||
-- defined in this configuration. Trusted providers are treated like self-hosted providers
|
||||
-- only for data-source security checks and related local data warnings.
|
||||
-- CONFIG["SETTINGS"]["DataSourceSecurity.TrustedProviderIds"] = {
|
||||
-- "00000000-0000-0000-0000-000000000000",
|
||||
-- "00000000-0000-0000-0000-000000000001",
|
||||
-- }
|
||||
|
||||
-- Example chat templates for this configuration:
|
||||
CONFIG["CHAT_TEMPLATES"] = {}
|
||||
|
||||
@ -77,6 +77,9 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract string Id { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ConfiguredProviderId { get; init; } = string.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public abstract string InstanceName { get; set; }
|
||||
|
||||
@ -18,6 +18,11 @@ public interface IProvider
|
||||
/// </summary>
|
||||
public string Id { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the configured provider instance.
|
||||
/// </summary>
|
||||
public string ConfiguredProviderId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The provider's instance name. Useful for multiple instances of the same provider,
|
||||
/// e.g., to distinguish between different OpenAI API keys.
|
||||
|
||||
@ -225,7 +225,7 @@ public static class LLMProvidersExtensions
|
||||
/// <returns>The provider instance.</returns>
|
||||
public static IProvider CreateProvider(this AIStudio.Settings.Provider providerSettings)
|
||||
{
|
||||
return providerSettings.UsedLLMProvider.CreateProvider(providerSettings.InstanceName, providerSettings.Host, providerSettings.Hostname, providerSettings.Model, providerSettings.HFInferenceProvider, providerSettings.AdditionalJsonApiParameters, providerSettings.IsEnterpriseConfiguration);
|
||||
return providerSettings.UsedLLMProvider.CreateProvider(providerSettings.InstanceName, providerSettings.Host, providerSettings.Hostname, providerSettings.Model, providerSettings.HFInferenceProvider, providerSettings.Id, providerSettings.AdditionalJsonApiParameters, providerSettings.IsEnterpriseConfiguration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -235,7 +235,7 @@ public static class LLMProvidersExtensions
|
||||
/// <returns>The provider instance.</returns>
|
||||
public static IProvider CreateProvider(this EmbeddingProvider embeddingProviderSettings)
|
||||
{
|
||||
return embeddingProviderSettings.UsedLLMProvider.CreateProvider(embeddingProviderSettings.Name, embeddingProviderSettings.Host, embeddingProviderSettings.Hostname, embeddingProviderSettings.Model, HFInferenceProvider.NONE, isEnterpriseConfiguration: embeddingProviderSettings.IsEnterpriseConfiguration);
|
||||
return embeddingProviderSettings.UsedLLMProvider.CreateProvider(embeddingProviderSettings.Name, embeddingProviderSettings.Host, embeddingProviderSettings.Hostname, embeddingProviderSettings.Model, HFInferenceProvider.NONE, configuredProviderId: embeddingProviderSettings.Id, isEnterpriseConfiguration: embeddingProviderSettings.IsEnterpriseConfiguration);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -245,33 +245,33 @@ public static class LLMProvidersExtensions
|
||||
/// <returns>The provider instance.</returns>
|
||||
public static IProvider CreateProvider(this TranscriptionProvider transcriptionProviderSettings)
|
||||
{
|
||||
return transcriptionProviderSettings.UsedLLMProvider.CreateProvider(transcriptionProviderSettings.Name, transcriptionProviderSettings.Host, transcriptionProviderSettings.Hostname, transcriptionProviderSettings.Model, HFInferenceProvider.NONE, isEnterpriseConfiguration: transcriptionProviderSettings.IsEnterpriseConfiguration);
|
||||
return transcriptionProviderSettings.UsedLLMProvider.CreateProvider(transcriptionProviderSettings.Name, transcriptionProviderSettings.Host, transcriptionProviderSettings.Hostname, transcriptionProviderSettings.Model, HFInferenceProvider.NONE, configuredProviderId: transcriptionProviderSettings.Id, isEnterpriseConfiguration: transcriptionProviderSettings.IsEnterpriseConfiguration);
|
||||
}
|
||||
|
||||
private static IProvider CreateProvider(this LLMProviders provider, string instanceName, Host host, string hostname, Model model, HFInferenceProvider inferenceProvider, string expertProviderApiParameter = "", bool isEnterpriseConfiguration = false)
|
||||
private static IProvider CreateProvider(this LLMProviders provider, string instanceName, Host host, string hostname, Model model, HFInferenceProvider inferenceProvider, string configuredProviderId = "", string expertProviderApiParameter = "", bool isEnterpriseConfiguration = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
return provider switch
|
||||
{
|
||||
LLMProviders.OPEN_AI => new ProviderOpenAI { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.ANTHROPIC => new ProviderAnthropic { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.MISTRAL => new ProviderMistral { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.GOOGLE => new ProviderGoogle { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.X => new ProviderX { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.DEEP_SEEK => new ProviderDeepSeek { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.ALIBABA_CLOUD => new ProviderAlibabaCloud { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.PERPLEXITY => new ProviderPerplexity { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.OPEN_ROUTER => new ProviderOpenRouter { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.OPEN_AI => new ProviderOpenAI { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.ANTHROPIC => new ProviderAnthropic { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.MISTRAL => new ProviderMistral { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.GOOGLE => new ProviderGoogle { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.X => new ProviderX { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.DEEP_SEEK => new ProviderDeepSeek { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.ALIBABA_CLOUD => new ProviderAlibabaCloud { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.PERPLEXITY => new ProviderPerplexity { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.OPEN_ROUTER => new ProviderOpenRouter { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
|
||||
LLMProviders.GROQ => new ProviderGroq { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.FIREWORKS => new ProviderFireworks { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.HUGGINGFACE => new ProviderHuggingFace(inferenceProvider, model) { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.GROQ => new ProviderGroq { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.FIREWORKS => new ProviderFireworks { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.HUGGINGFACE => new ProviderHuggingFace(inferenceProvider, model) { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
|
||||
LLMProviders.SELF_HOSTED => new ProviderSelfHosted(host, hostname) { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.SELF_HOSTED => new ProviderSelfHosted(host, hostname) { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
|
||||
LLMProviders.HELMHOLTZ => new ProviderHelmholtz { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.GWDG => new ProviderGWDG { InstanceName = instanceName, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.HELMHOLTZ => new ProviderHelmholtz { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
LLMProviders.GWDG => new ProviderGWDG { InstanceName = instanceName, ConfiguredProviderId = configuredProviderId, AdditionalJsonApiParameters = expertProviderApiParameter, IsEnterpriseConfiguration = isEnterpriseConfiguration },
|
||||
|
||||
_ => new NoProvider(),
|
||||
};
|
||||
|
||||
@ -13,6 +13,8 @@ public class NoProvider : IProvider
|
||||
|
||||
public string Id => "none";
|
||||
|
||||
public string ConfiguredProviderId => string.Empty;
|
||||
|
||||
public string InstanceName { get; set; } = "None";
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@ -23,6 +23,11 @@ public sealed class Data
|
||||
/// </summary>
|
||||
public DataConfidence Confidence { get; init; } = new(x => x.Confidence);
|
||||
|
||||
/// <summary>
|
||||
/// Settings concerning data source security checks.
|
||||
/// </summary>
|
||||
public DataSourceSecuritySettings DataSourceSecurity { get; init; } = new(x => x.DataSourceSecurity);
|
||||
|
||||
/// <summary>
|
||||
/// A collection of embedding providers configured.
|
||||
/// </summary>
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
using System.Linq.Expressions;
|
||||
|
||||
using AIStudio.Settings.DataModel;
|
||||
|
||||
namespace AIStudio.Settings;
|
||||
|
||||
public sealed class DataSourceSecuritySettings(Expression<Func<Data, DataSourceSecuritySettings>>? configSelection = null)
|
||||
{
|
||||
/// <summary>
|
||||
/// The default constructor for the JSON deserializer.
|
||||
/// </summary>
|
||||
public DataSourceSecuritySettings() : this(null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provider instance IDs trusted by an organization for data-source security checks.
|
||||
/// </summary>
|
||||
public HashSet<string> TrustedProviderIds { get; set; } = ManagedConfiguration.Register(configSelection, n => n.TrustedProviderIds, []);
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
using AIStudio.Provider;
|
||||
|
||||
namespace AIStudio.Settings;
|
||||
|
||||
public static class DataSourceSecurityTrustExtensions
|
||||
{
|
||||
public static bool IsTrustedForDataSourceSecurityChecks(this Provider provider, SettingsManager settingsManager)
|
||||
{
|
||||
if (provider == Provider.NONE)
|
||||
return false;
|
||||
|
||||
return provider.IsSelfHosted || IsTrustedProviderId(provider.Id, settingsManager);
|
||||
}
|
||||
|
||||
public static bool IsTrustedForDataSourceSecurityChecks(this EmbeddingProvider provider, SettingsManager settingsManager)
|
||||
{
|
||||
if (provider == EmbeddingProvider.NONE)
|
||||
return false;
|
||||
|
||||
return provider.IsSelfHosted || IsTrustedProviderId(provider.Id, settingsManager);
|
||||
}
|
||||
|
||||
public static bool IsTrustedForDataSourceSecurityChecks(this TranscriptionProvider provider, SettingsManager settingsManager)
|
||||
{
|
||||
if (provider == TranscriptionProvider.NONE)
|
||||
return false;
|
||||
|
||||
return provider.IsSelfHosted || IsTrustedProviderId(provider.Id, settingsManager);
|
||||
}
|
||||
|
||||
public static bool IsTrustedForDataSourceSecurityChecks(this IProvider provider, SettingsManager settingsManager)
|
||||
{
|
||||
if (provider is NoProvider)
|
||||
return false;
|
||||
|
||||
return provider.Provider is LLMProviders.SELF_HOSTED || IsTrustedProviderId(provider.ConfiguredProviderId, settingsManager);
|
||||
}
|
||||
|
||||
private static bool IsTrustedProviderId(string providerId, SettingsManager settingsManager)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(providerId))
|
||||
return false;
|
||||
|
||||
return settingsManager.ConfigurationData.DataSourceSecurity.TrustedProviderIds.Any(id => string.Equals(id, providerId, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
@ -483,6 +483,7 @@ public sealed class SettingsManager
|
||||
throw new ArgumentException("Expression must be a property access", nameof(propertyExpression));
|
||||
|
||||
// Return the full name of the property, including the class name:
|
||||
return $"{typeof(TIn).Name}.{memberExpr.Member.Name}";
|
||||
var typeName = typeof(TIn) == typeof(DataSourceSecuritySettings) ? "DataSourceSecurity" : typeof(TIn).Name;
|
||||
return $"{typeName}.{memberExpr.Member.Name}";
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,6 +201,9 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.Confidence, x => x.ShowProviderConfidence, this.Id, settingsTable, dryRun);
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.Confidence, x => x.ConfidenceScheme, this.Id, settingsTable, dryRun);
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.Confidence, x => x.CustomConfidenceScheme, this.Id, settingsTable, dryRun);
|
||||
|
||||
// Config: data source security settings
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.DataSourceSecurity, x => x.TrustedProviderIds, this.Id, settingsTable, dryRun);
|
||||
|
||||
// Handle configured LLM providers:
|
||||
PluginConfigurationObject.TryParse(PluginConfigurationObjectType.LLM_PROVIDER, x => x.Providers, x => x.NextProviderNum, mainTable, this.Id, ref this.configObjects, dryRun);
|
||||
|
||||
@ -283,6 +283,10 @@ public static partial class PluginFactory
|
||||
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.Confidence, x => x.CustomConfidenceScheme, AVAILABLE_PLUGINS))
|
||||
wasConfigurationChanged = true;
|
||||
|
||||
// Check data source security settings:
|
||||
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.DataSourceSecurity, x => x.TrustedProviderIds, AVAILABLE_PLUGINS))
|
||||
wasConfigurationChanged = true;
|
||||
|
||||
// Check if audit is required before it can be activated
|
||||
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.AssistantPluginAudit, x => x.RequireAuditBeforeActivation, AVAILABLE_PLUGINS))
|
||||
wasConfigurationChanged = true;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
using AIStudio.Assistants.ERI;
|
||||
using AIStudio.Provider;
|
||||
using AIStudio.Provider.SelfHosted;
|
||||
using AIStudio.Settings;
|
||||
using AIStudio.Settings.DataModel;
|
||||
using AIStudio.Tools.ERIClient;
|
||||
@ -43,7 +42,7 @@ public sealed class DataSourceService
|
||||
return new([], []);
|
||||
}
|
||||
|
||||
return await this.GetDataSources(selectedLLMProvider.IsSelfHosted, previousSelectedDataSources);
|
||||
return await this.GetDataSources(selectedLLMProvider.IsTrustedForDataSourceSecurityChecks(this.settingsManager), previousSelectedDataSources);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -66,10 +65,10 @@ public sealed class DataSourceService
|
||||
return new([], []);
|
||||
}
|
||||
|
||||
return await this.GetDataSources(selectedLLMProvider is ProviderSelfHosted, previousSelectedDataSources);
|
||||
return await this.GetDataSources(selectedLLMProvider.IsTrustedForDataSourceSecurityChecks(this.settingsManager), previousSelectedDataSources);
|
||||
}
|
||||
|
||||
private async Task<AllowedSelectedDataSources> GetDataSources(bool usingSelfHostedProvider, IReadOnlyCollection<IDataSource>? previousSelectedDataSources = null)
|
||||
private async Task<AllowedSelectedDataSources> GetDataSources(bool usingTrustedProvider, IReadOnlyCollection<IDataSource>? previousSelectedDataSources = null)
|
||||
{
|
||||
var allDataSources = this.settingsManager.ConfigurationData.DataSources;
|
||||
var filteredDataSources = new List<IDataSource>(allDataSources.Count);
|
||||
@ -78,7 +77,7 @@ public sealed class DataSourceService
|
||||
|
||||
// Start all checks in parallel:
|
||||
foreach (var source in allDataSources)
|
||||
tasks.Add(this.CheckOneDataSource(source, usingSelfHostedProvider));
|
||||
tasks.Add(this.CheckOneDataSource(source, usingTrustedProvider));
|
||||
|
||||
// Wait for all checks and collect the results:
|
||||
foreach (var task in tasks)
|
||||
@ -95,7 +94,7 @@ public sealed class DataSourceService
|
||||
return new(filteredDataSources, filteredSelectedDataSources);
|
||||
}
|
||||
|
||||
private async Task<IDataSource?> CheckOneDataSource(IDataSource source, bool usingSelfHostedProvider)
|
||||
private async Task<IDataSource?> CheckOneDataSource(IDataSource source, bool usingTrustedProvider)
|
||||
{
|
||||
//
|
||||
// Unfortunately, we have to live-check any ERI source for its security requirements.
|
||||
@ -137,10 +136,10 @@ public sealed class DataSourceService
|
||||
case DataSourceSecurity.ALLOW_ANY:
|
||||
|
||||
//
|
||||
// Case: The data source allows any provider type. We want to use a self-hosted provider.
|
||||
// Case: The data source allows any provider type. We want to use a trusted provider.
|
||||
// There is no issue with this source. Accept it.
|
||||
//
|
||||
if(usingSelfHostedProvider)
|
||||
if(usingTrustedProvider)
|
||||
return source;
|
||||
|
||||
//
|
||||
@ -151,13 +150,13 @@ public sealed class DataSourceService
|
||||
return source;
|
||||
|
||||
//
|
||||
// Case: The ERI source requires a self-hosted provider. This misconfiguration happens
|
||||
// Case: The ERI source requires a self-hosted or organization-trusted provider. This misconfiguration happens
|
||||
// when the ERI server operator changes the security requirements. The ERI server
|
||||
// operator owns the data -- we have to respect their rules. We skip this source.
|
||||
//
|
||||
if (eriSourceRequirements is { AllowedProviderType: ProviderType.SELF_HOSTED })
|
||||
{
|
||||
this.logger.LogWarning($"The ERI source '{source.Name}' (id={source.Id}) requires a self-hosted provider. We skip this source.");
|
||||
this.logger.LogWarning($"The ERI source '{source.Name}' (id={source.Id}) requires a self-hosted or organization-trusted provider. We skip this source.");
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -171,22 +170,22 @@ public sealed class DataSourceService
|
||||
//
|
||||
// Case: Missing rules. We skip this source. Better safe than sorry.
|
||||
//
|
||||
this.logger.LogDebug($"The ERI source '{source.Name}' (id={source.Id}) was filtered out due to missing rules.");
|
||||
this.logger.LogWarning($"The ERI source '{source.Name}' (id={source.Id}) was filtered out due to missing rules.");
|
||||
return null;
|
||||
|
||||
//
|
||||
// Case: The data source requires a self-hosted provider. We want to use a self-hosted provider.
|
||||
// Case: The data source requires a trusted provider. We want to use a trusted provider.
|
||||
// There is no issue with this source. Accept it.
|
||||
//
|
||||
case DataSourceSecurity.SELF_HOSTED when usingSelfHostedProvider:
|
||||
case DataSourceSecurity.SELF_HOSTED when usingTrustedProvider:
|
||||
return source;
|
||||
|
||||
//
|
||||
// Case: The data source requires a self-hosted provider. We want to use a cloud provider.
|
||||
// Case: The data source requires a trusted provider. We want to use an untrusted provider.
|
||||
// We skip this source.
|
||||
//
|
||||
case DataSourceSecurity.SELF_HOSTED when !usingSelfHostedProvider:
|
||||
this.logger.LogWarning($"The data source '{source.Name}' (id={source.Id}) requires a self-hosted provider. We skip this source.");
|
||||
case DataSourceSecurity.SELF_HOSTED when !usingTrustedProvider:
|
||||
this.logger.LogWarning($"The data source '{source.Name}' (id={source.Id}) requires a self-hosted or organization-trusted provider. We skip this source.");
|
||||
return null;
|
||||
|
||||
//
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
- Added a read-only view for organization-managed profiles and chat templates, so users can inspect the content while the organization remains in control of changes.
|
||||
- Added support for organization-managed introduction texts on the home page. Configuration plugins can now add custom Markdown introductions and hide the built-in introduction.
|
||||
- Added support for organization-managed provider confidence settings. Configuration plugins can now set confidence presets, custom confidence schemes, and an app-wide minimum confidence level.
|
||||
- Added support for organization-trusted providers in data source security checks. Configuration plugins can now mark specific provider instances as trusted for data source usage and local embedding warnings.
|
||||
- Changed provider confidence settings to appear in their own settings panel, because they apply to LLM, embedding, and transcription providers.
|
||||
- Fixed organization-managed chat templates not showing the correct icon in the chat template selection menu.
|
||||
- Fixed self-hosted provider API keys sometimes being stored under a localized name. AI Studio now uses a stable key name, keeps correct entries working, and automatically migrates known localized entries for LLM, transcription, and embedding providers. Organizations using configuration plugins do not need to change their plugins; affected users who still see an invalid API key warning should open the provider, transcription, or embedding settings and update the API key once.
|
||||
Loading…
Reference in New Issue
Block a user