mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-04 11:27:21 +00:00
Added a way for organizations to prohibit providers (#1105)
This commit is contained in:
1 parent
052868b24e
commit
7ba5f01388
38 files changed
+1488
-629
No files matched your search
@@ -255,6 +255,14 @@ public sealed class AIJobService(SettingsManager settingsManager, MessageBus mes
|
||||
var provider = request.ProviderSettings.CreateProvider();
|
||||
var chatThread = request.ChatThread;
|
||||
|
||||
// Checked on its own, so that the user learns what to change:
|
||||
if (settingsManager.IsProviderProhibited(request.ProviderSettings.UsedLLMProvider))
|
||||
{
|
||||
logger.LogError("The provider of chat '{ChatId}' is prohibited by the organization. Skipping the AI process.", chatThread.ChatId);
|
||||
await this.CompleteChatGenerationAsync(state, AIJobStatus.FAILED, TB("The use of this provider has been prohibited by your organization. Please select a different provider."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!chatThread.IsLLMProviderAllowed(provider))
|
||||
{
|
||||
logger.LogError("The provider is not allowed for chat '{ChatId}' due to data security reasons. Skipping the AI process.", chatThread.ChatId);
|
||||
|
||||
@@ -330,6 +330,9 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT
|
||||
|
||||
// Config: hide some assistants?
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.HiddenAssistants, this.Id, settingsTable, dryRun);
|
||||
|
||||
// Config: prohibit some providers?
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.ProhibitedProviders, this.Id, settingsTable, dryRun);
|
||||
|
||||
// Config: global voice recording shortcut
|
||||
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.ShortcutVoiceRecording, this.Id, settingsTable, dryRun);
|
||||
|
||||
@@ -333,6 +333,10 @@ public static partial class PluginFactory
|
||||
if(ManagedConfiguration.CleanupLeftOverManagedConfigurations(AVAILABLE_PLUGINS, deployedEnterpriseConfigPluginIds))
|
||||
wasConfigurationChanged = true;
|
||||
|
||||
// Every configuration plugin has run and the left-overs are gone, so the result no longer
|
||||
// depends on the order in which the plugins ran:
|
||||
LogConfidenceLevelsOutrankedByProhibitions();
|
||||
|
||||
//
|
||||
// The enterprise approvals of all configuration plugins add up. Now that every plugin has
|
||||
// contributed and the clean-up above has dropped the removed ones, we rebuild the effective
|
||||
@@ -365,6 +369,28 @@ public static partial class PluginFactory
|
||||
FIRST_LOAD_COMPLETED.TrySetResult();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs the confidence levels which a configuration plugin chose for prohibited providers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A prohibited provider is untrusted, whatever level the custom confidence scheme names for it, see
|
||||
/// SettingsManager.GetConfiguredConfidenceLevel. Such a level contradicts the prohibition, so we tell
|
||||
/// the organization that it is ignored. Levels the user chose are ignored the same way, without a log.
|
||||
/// </remarks>
|
||||
private static void LogConfidenceLevelsOutrankedByProhibitions()
|
||||
{
|
||||
if (!ManagedConfiguration.TryGet(x => x.Confidence, x => x.CustomConfidenceScheme, out var configMeta))
|
||||
return;
|
||||
|
||||
var owningConfigPluginId = ManagedConfiguration.GetSettingOwner(configMeta);
|
||||
if (owningConfigPluginId == Guid.Empty)
|
||||
return;
|
||||
|
||||
var customConfidenceScheme = SettingsManagerAccess.ConfigurationData.Confidence.CustomConfidenceScheme;
|
||||
foreach (var llmProvider in SettingsManagerAccess.GetProhibitedProvidersWithCustomConfidenceLevel())
|
||||
LOG.LogWarning($"The configuration plugin '{owningConfigPluginId}' sets the confidence level '{customConfidenceScheme[llmProvider]}' for the provider '{llmProvider}' in the custom confidence scheme. Ignoring it: your organization prohibited this provider, so it is untrusted.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the IDs of all configuration plugins which an organization deployed on this machine.
|
||||
/// </summary>
|
||||
|
||||
@@ -7,12 +7,30 @@ namespace AIStudio.Tools.Services;
|
||||
|
||||
internal static class DataSourceEmbeddingProviders
|
||||
{
|
||||
/// <summary>
|
||||
/// Finds the embedding provider of a data source, when AI Studio may use it.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A provider the organization prohibited counts as missing: nothing may be embedded with it,
|
||||
/// neither the documents of the data source nor a query against its index.
|
||||
/// </remarks>
|
||||
public static bool TryResolve(SettingsManager settingsManager, IDataSourceBase dataSource, [NotNullWhen(true)] out EmbeddingProvider? embeddingProvider)
|
||||
{
|
||||
embeddingProvider = settingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(provider =>
|
||||
dataSource is IIndexedDataSource indexedDataSource &&
|
||||
provider.Id.Equals(indexedDataSource.EmbeddingId, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
return embeddingProvider != default && embeddingProvider.UsedLLMProvider is not LLMProviders.NONE;
|
||||
embeddingProvider = Find(settingsManager, dataSource);
|
||||
return embeddingProvider is { UsedLLMProvider: not LLMProviders.NONE } && !settingsManager.IsProviderProhibited(embeddingProvider.UsedLLMProvider);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the organization prohibited the embedding provider of a data source.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// TryResolve fails for such a provider as well, but without the reason. The status of a data
|
||||
/// source needs the reason to tell the user what to change.
|
||||
/// </remarks>
|
||||
public static bool IsProhibited(SettingsManager settingsManager, IDataSourceBase dataSource)
|
||||
=> Find(settingsManager, dataSource) is { } embeddingProvider && settingsManager.IsProviderProhibited(embeddingProvider.UsedLLMProvider);
|
||||
|
||||
private static EmbeddingProvider? Find(SettingsManager settingsManager, IDataSourceBase dataSource) => settingsManager.ConfigurationData.EmbeddingProviders.FirstOrDefault(provider =>
|
||||
dataSource is IIndexedDataSource indexedDataSource &&
|
||||
provider.Id.Equals(indexedDataSource.EmbeddingId, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
@@ -801,7 +801,9 @@ public sealed partial class DataSourceEmbeddingService(SettingsManager settingsM
|
||||
if (!this.TryResolveEmbeddingProvider(dataSource, out var embeddingProvider))
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
this.UpsertStatus(this.GetFallbackStatus(dataSource, TB("The selected embedding provider is not available. Please check it in the settings.")));
|
||||
this.UpsertStatus(this.GetFallbackStatus(dataSource, DataSourceEmbeddingProviders.IsProhibited(settingsManager, dataSource)
|
||||
? TB("The use of the embedding provider of this data source has been prohibited by your organization. Please select a different embedding provider in the settings of the data source.")
|
||||
: TB("The selected embedding provider is not available. Please check it in the settings.")));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -754,10 +754,11 @@ public sealed class MediaTranscriptionService(
|
||||
|
||||
/// <summary>Resolves the configured provider after confidence validation.</summary>
|
||||
/// <remarks>
|
||||
/// Checks the global minimum confidence only. A caller with rules of its own, such as the
|
||||
/// confidence level of a data source, checks the provider against them as well.
|
||||
/// Checks the global minimum confidence and whether the organization prohibited the provider. A
|
||||
/// caller with rules of its own, such as the confidence level of a data source, checks the
|
||||
/// provider against them as well.
|
||||
/// </remarks>
|
||||
/// <returns>The configured provider, or null when none is configured or it falls short of the global minimum.</returns>
|
||||
/// <returns>The configured provider, or null when none is configured, it falls short of the global minimum, or it is prohibited.</returns>
|
||||
public TranscriptionProvider? GetUsableProvider()
|
||||
{
|
||||
var providerId = settingsManager.ConfigurationData.App.UseTranscriptionProvider;
|
||||
@@ -769,7 +770,7 @@ public sealed class MediaTranscriptionService(
|
||||
return null;
|
||||
|
||||
var minimumLevel = settingsManager.GetMinimumConfidenceLevel(Components.NONE);
|
||||
return providerSettings.UsedLLMProvider.GetConfidence(settingsManager).Level >= minimumLevel
|
||||
return settingsManager.IsProviderUsable(providerSettings.UsedLLMProvider, minimumLevel)
|
||||
? providerSettings
|
||||
: null;
|
||||
}
|
||||
|
||||
@@ -19,14 +19,19 @@ public static class PendingUserAPIKeys
|
||||
/// <returns>One group per configuration plugin with at least one waiting provider.</returns>
|
||||
public static async Task<IReadOnlyList<PendingUserAPIKeyGroup>> FindAsync(SettingsManager settingsManager, RustService rustService)
|
||||
{
|
||||
//
|
||||
// A provider the organization prohibited is left out, even when a configuration of the same
|
||||
// organization asks for its key: the key could be used for nothing, and checking it would
|
||||
// contact the provider.
|
||||
//
|
||||
var candidates = new List<(Guid ConfigPluginId, PendingUserAPIKeyTarget Target)>();
|
||||
foreach (var provider in settingsManager.GetAllProviders().Where(provider => IsPrompting(provider)))
|
||||
foreach (var provider in settingsManager.GetAllProviders().Where(provider => IsPrompting(provider) && !settingsManager.IsProviderProhibited(provider.UsedLLMProvider)))
|
||||
candidates.Add((provider.EnterpriseConfigurationPluginId, new PendingUserAPIKeyTarget(provider.InstanceName, provider, SecretStoreType.LLM_PROVIDER, () => provider.CreateProvider())));
|
||||
|
||||
foreach (var provider in settingsManager.GetAllEmbeddingProviders().Where(provider => IsPrompting(provider)))
|
||||
foreach (var provider in settingsManager.GetAllEmbeddingProviders().Where(provider => IsPrompting(provider) && !settingsManager.IsProviderProhibited(provider.UsedLLMProvider)))
|
||||
candidates.Add((provider.EnterpriseConfigurationPluginId, new PendingUserAPIKeyTarget(provider.Name, provider, SecretStoreType.EMBEDDING_PROVIDER, () => provider.CreateProvider())));
|
||||
|
||||
foreach (var provider in settingsManager.GetAllTranscriptionProviders().Where(provider => IsPrompting(provider)))
|
||||
foreach (var provider in settingsManager.GetAllTranscriptionProviders().Where(provider => IsPrompting(provider) && !settingsManager.IsProviderProhibited(provider.UsedLLMProvider)))
|
||||
candidates.Add((provider.EnterpriseConfigurationPluginId, new PendingUserAPIKeyTarget(provider.Name, provider, SecretStoreType.TRANSCRIPTION_PROVIDER, () => provider.CreateProvider())));
|
||||
|
||||
if (candidates.Count == 0)
|
||||
|
||||
@@ -188,9 +188,13 @@ public sealed class DataSourceValidation
|
||||
// An id which matches no provider belongs to one which was deleted since. Saved like this, the
|
||||
// data source keeps pointing at a provider nobody can reach, and nothing of it is embedded:
|
||||
//
|
||||
if(this.GetSelectedEmbeddingProvider() is null)
|
||||
if(this.GetSelectedEmbeddingProvider() is not { } selectedEmbedding)
|
||||
return TB("The embedding provider of this data source no longer exists. Please select another one.");
|
||||
|
||||
// Saved like this, nothing of the data source would ever be embedded:
|
||||
if(this.GetSettingsManager() is { } settingsManager && settingsManager.IsProviderProhibited(selectedEmbedding.UsedLLMProvider))
|
||||
return TB("The use of this embedding provider has been prohibited by your organization. Please select a different embedding provider.");
|
||||
|
||||
return this.ValidateSelectedEmbeddingProviderAccess();
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user