AI-Studio/app/MindWork AI Studio/Settings/SettingsManager.cs

581 lines
24 KiB
C#
Raw Normal View History

using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
2024-04-19 19:19:13 +00:00
using System.Text.Json;
2024-07-28 19:18:17 +00:00
2024-09-11 21:08:02 +00:00
using AIStudio.Provider;
using AIStudio.Settings.DataModel;
using AIStudio.Tools;
using AIStudio.Tools.ToolCallingSystem;
2025-03-29 17:40:17 +00:00
using AIStudio.Tools.PluginSystem;
using AIStudio.Tools.Services;
2024-04-19 19:19:13 +00:00
2024-04-20 15:06:50 +00:00
// ReSharper disable NotAccessedPositionalProperty.Local
2024-04-19 19:19:13 +00:00
namespace AIStudio.Settings;
2024-05-04 08:55:00 +00:00
/// <summary>
/// The settings manager.
/// </summary>
2025-05-03 19:47:43 +00:00
public sealed class SettingsManager
2024-04-19 19:19:13 +00:00
{
2026-06-11 14:25:26 +00:00
public readonly record struct ToolMinimumProviderConfidenceResolution(ConfidenceLevel ConfidenceLevel, string Source);
2024-04-19 19:19:13 +00:00
private const string SETTINGS_FILENAME = "settings.json";
2024-07-28 19:18:17 +00:00
private static readonly JsonSerializerOptions JSON_OPTIONS = new()
{
WriteIndented = true,
Converters = { new TolerantEnumConverter() },
2024-07-28 19:18:17 +00:00
};
2024-09-01 18:10:03 +00:00
2025-05-03 19:47:43 +00:00
private readonly ILogger<SettingsManager> logger;
private readonly RustService rustService;
/// <summary>
/// The settings manager.
/// </summary>
public SettingsManager(ILogger<SettingsManager> logger, RustService rustService)
{
this.logger = logger;
this.rustService = rustService;
this.logger.LogInformation("Settings manager created.");
}
2024-05-04 08:55:00 +00:00
/// <summary>
/// The directory where the configuration files are stored.
/// </summary>
2024-04-19 19:19:13 +00:00
public static string? ConfigDirectory { get; set; }
2024-05-04 08:55:00 +00:00
/// <summary>
/// The directory where the data files are stored.
/// </summary>
2024-04-19 19:19:13 +00:00
public static string? DataDirectory { get; set; }
/// <summary>
/// Whether the app is in dark mode.
/// </summary>
public bool IsDarkMode { get; set; }
/// <summary>
/// Ensures that the startup start-page redirect is evaluated at most once per app session.
/// </summary>
public bool StartupStartPageRedirectHandled { get; set; }
/// <summary>
/// Indicates that the initial settings load attempt has completed.
/// </summary>
public bool HasCompletedInitialSettingsLoad { get; private set; }
2024-05-04 08:55:00 +00:00
/// <summary>
/// The configuration data.
/// </summary>
2024-04-20 15:06:50 +00:00
public Data ConfigurationData { get; private set; } = new();
private bool IsSetUp => !string.IsNullOrWhiteSpace(ConfigDirectory) && !string.IsNullOrWhiteSpace(DataDirectory);
2024-05-04 08:55:00 +00:00
/// <summary>
/// Loads the settings from the file system.
/// </summary>
2024-04-20 15:06:50 +00:00
public async Task LoadSettings()
2026-03-10 19:50:45 +00:00
{
var settingsSnapshot = await this.TryReadSettingsSnapshot();
if (settingsSnapshot is not null)
this.ConfigurationData = settingsSnapshot;
this.HasCompletedInitialSettingsLoad = true;
2026-03-10 19:50:45 +00:00
}
/// <summary>
/// Reads the settings from disk without mutating the current in-memory state.
/// </summary>
/// <returns>A (migrated) settings snapshot, or null if it could not be read.</returns>
public async Task<Data?> TryReadSettingsSnapshot()
2024-04-19 19:19:13 +00:00
{
if(!this.IsSetUp)
2024-09-01 18:10:03 +00:00
{
this.logger.LogWarning("Cannot load settings, because the configuration is not set up yet.");
2026-03-10 19:50:45 +00:00
return null;
2024-09-01 18:10:03 +00:00
}
2024-04-19 19:19:13 +00:00
var settingsPath = Path.Combine(ConfigDirectory!, SETTINGS_FILENAME);
if(!File.Exists(settingsPath))
2024-09-01 18:10:03 +00:00
{
this.logger.LogWarning("Cannot load settings, because the settings file does not exist.");
2026-03-10 19:50:45 +00:00
return null;
2024-09-01 18:10:03 +00:00
}
2024-08-05 19:12:52 +00:00
// We read the `"Version": "V3"` line to determine the version of the settings file:
await foreach (var line in File.ReadLinesAsync(settingsPath))
{
if (!line.Contains("""
"Version":
"""))
continue;
// Extract the version from the line:
var settingsVersionText = line.Split('"')[3];
2026-03-10 19:50:45 +00:00
2024-08-05 19:12:52 +00:00
// Parse the version:
Enum.TryParse(settingsVersionText, out Version settingsVersion);
if(settingsVersion is Version.UNKNOWN)
{
2024-09-01 18:10:03 +00:00
this.logger.LogError("Unknown version of the settings file found.");
2026-03-10 19:50:45 +00:00
return new();
2024-08-05 19:12:52 +00:00
}
2026-03-10 19:50:45 +00:00
var settingsData = SettingsMigrations.Migrate(this.logger, settingsVersion, await File.ReadAllTextAsync(settingsPath), JSON_OPTIONS);
//
// We filter the enabled preview features based on the preview visibility.
// This is necessary when the app starts up: some preview features may have
// been disabled or released from the last time the app was started.
//
2026-03-10 19:50:45 +00:00
settingsData.App.EnabledPreviewFeatures = settingsData.App.PreviewVisibility.FilterPreviewFeatures(settingsData.App.EnabledPreviewFeatures);
return settingsData;
2024-08-05 19:12:52 +00:00
}
2026-03-10 19:50:45 +00:00
2024-09-01 18:10:03 +00:00
this.logger.LogError("Failed to read the version of the settings file.");
2026-03-10 19:50:45 +00:00
return new();
2024-04-19 19:19:13 +00:00
}
2024-04-20 15:06:50 +00:00
2024-05-04 08:55:00 +00:00
/// <summary>
/// Stores the settings to the file system.
/// </summary>
2024-04-20 15:06:50 +00:00
public async Task StoreSettings()
2024-04-19 19:19:13 +00:00
{
if(!this.IsSetUp)
2024-09-01 18:10:03 +00:00
{
this.logger.LogWarning("Cannot store settings, because the configuration is not set up yet.");
2024-04-19 19:19:13 +00:00
return;
2024-09-01 18:10:03 +00:00
}
2024-04-19 19:19:13 +00:00
var settingsPath = Path.Combine(ConfigDirectory!, SETTINGS_FILENAME);
2024-04-20 15:06:50 +00:00
if(!Directory.Exists(ConfigDirectory))
2024-09-01 18:10:03 +00:00
{
this.logger.LogInformation("Creating the configuration directory.");
2024-04-20 15:06:50 +00:00
Directory.CreateDirectory(ConfigDirectory!);
2024-09-01 18:10:03 +00:00
}
2024-07-28 19:18:17 +00:00
var settingsJson = JsonSerializer.Serialize(this.ConfigurationData, JSON_OPTIONS);
var tempFile = Path.GetTempFileName();
await File.WriteAllTextAsync(tempFile, settingsJson);
2024-09-01 18:10:03 +00:00
File.Move(tempFile, settingsPath, true);
2024-09-01 18:10:03 +00:00
this.logger.LogInformation("Stored the settings to the file system.");
2024-04-19 19:19:13 +00:00
}
2024-06-01 17:55:12 +00:00
2024-08-05 19:12:52 +00:00
public void InjectSpellchecking(Dictionary<string, object?> attributes) => attributes["spellcheck"] = this.ConfigurationData.App.EnableSpellchecking ? "true" : "false";
2024-09-04 13:44:23 +00:00
public ConfidenceLevel GetMinimumConfidenceLevel(Tools.Components component)
{
var minimumLevel = ConfidenceLevel.NONE;
var enforceGlobalMinimumConfidence = this.ConfigurationData.LLMProviders is { EnforceGlobalMinimumConfidence: true, GlobalMinimumConfidence: not ConfidenceLevel.NONE and not ConfidenceLevel.UNKNOWN };
if (enforceGlobalMinimumConfidence)
minimumLevel = this.ConfigurationData.LLMProviders.GlobalMinimumConfidence;
var componentMinimumLevel = component.MinimumConfidence(this);
if (componentMinimumLevel > minimumLevel)
minimumLevel = componentMinimumLevel;
return minimumLevel;
}
/// <summary>
/// Checks if the given plugin is enabled.
/// </summary>
/// <param name="plugin">The plugin to check.</param>
/// <returns>True, when the plugin is enabled, false otherwise.</returns>
public bool IsPluginEnabled(IPluginMetadata plugin) => plugin.Type is PluginType.CONFIGURATION || this.ConfigurationData.EnabledPlugins.Contains(plugin.Id);
2025-03-29 17:40:17 +00:00
/// <summary>
/// Returns the active language plugin.
/// </summary>
/// <returns>The active language plugin.</returns>
public async Task<ILanguagePlugin> GetActiveLanguagePlugin()
{
switch (this.ConfigurationData.App.LanguageBehavior)
{
case LangBehavior.AUTO:
var languageCode = await this.rustService.ReadUserLanguage();
var languagePlugins = PluginFactory.RunningPlugins.OfType<ILanguagePlugin>().ToList();
if (!string.IsNullOrWhiteSpace(languageCode))
2025-04-27 07:06:05 +00:00
{
var exactMatch = languagePlugins.FirstOrDefault(x => string.Equals(x.IETFTag, languageCode, StringComparison.OrdinalIgnoreCase));
if (exactMatch is not null)
return exactMatch;
var primaryLanguage = GetPrimaryLanguage(languageCode);
if (!string.IsNullOrWhiteSpace(primaryLanguage))
{
var primaryLanguageMatch = languagePlugins
.Where(x => string.Equals(GetPrimaryLanguage(x.IETFTag), primaryLanguage, StringComparison.OrdinalIgnoreCase))
.OrderBy(x => x.IETFTag, StringComparer.OrdinalIgnoreCase)
.FirstOrDefault();
if (primaryLanguageMatch is not null)
{
this.logger.LogWarning($"No exact language plugin found for '{languageCode}'. Use language fallback '{primaryLanguageMatch.IETFTag}'.");
return primaryLanguageMatch;
}
}
2025-04-27 07:06:05 +00:00
}
this.logger.LogWarning($"The language plugin for the language '{languageCode}' (normalized='{languageCode}') is not available.");
return PluginFactory.BaseLanguage;
case LangBehavior.MANUAL:
var pluginId = this.ConfigurationData.App.LanguagePluginId;
var plugin = PluginFactory.RunningPlugins.FirstOrDefault(x => x.Id == pluginId);
if (plugin is null)
{
this.logger.LogWarning($"The chosen language plugin (id='{pluginId}') is not available.");
return PluginFactory.BaseLanguage;
}
if (plugin is ILanguagePlugin chosenLangPlugin)
return chosenLangPlugin;
2025-04-27 07:06:05 +00:00
this.logger.LogError("The chosen language plugin is not a language plugin.");
return PluginFactory.BaseLanguage;
}
this.logger.LogError("The language behavior is unknown.");
return PluginFactory.BaseLanguage;
}
private static string GetPrimaryLanguage(string localeTag)
{
if (string.IsNullOrWhiteSpace(localeTag))
return string.Empty;
var separatorIndex = localeTag.IndexOf('-');
if (separatorIndex < 0)
return localeTag;
return localeTag[..separatorIndex];
}
[SuppressMessage("Usage", "MWAIS0001:Direct access to `Providers` is not allowed")]
public Provider GetPreselectedProvider(Tools.Components component, string? currentProviderId = null, bool usePreselectionBeforeCurrentProvider = false)
2024-09-04 13:44:23 +00:00
{
var minimumLevel = this.GetMinimumConfidenceLevel(component);
// When there is only one provider, and it has a confidence level that is high enough, we return it:
if (this.ConfigurationData.Providers.Count == 1 && this.ConfigurationData.Providers[0].UsedLLMProvider.GetConfidence(this).Level >= minimumLevel)
2024-09-04 13:44:23 +00:00
return this.ConfigurationData.Providers[0];
// Is there a current provider with a sufficiently high confidence level?
var currentProvider = Provider.NONE;
if (currentProviderId is not null && !string.IsNullOrWhiteSpace(currentProviderId))
2024-11-23 12:04:02 +00:00
{
var currentProviderProbe = this.ConfigurationData.Providers.FirstOrDefault(x => x.Id == currentProviderId);
if (currentProviderProbe is not null && currentProviderProbe.UsedLLMProvider.GetConfidence(this).Level >= minimumLevel)
currentProvider = currentProviderProbe;
2024-11-23 12:04:02 +00:00
}
// Is there a component-preselected provider with a sufficiently high confidence level?
var preselectedProvider = Provider.NONE;
var preselectedProviderProbe = component.PreselectedProvider(this);
if(preselectedProviderProbe != Provider.NONE && preselectedProviderProbe.UsedLLMProvider.GetConfidence(this).Level >= minimumLevel)
preselectedProvider = preselectedProviderProbe;
//
// Case: The preselected provider should be used before the current provider,
// and the preselected provider is available and has a confidence level
// that is high enough.
//
if(usePreselectionBeforeCurrentProvider && preselectedProvider != Provider.NONE)
return preselectedProvider;
//
// Case: The current provider is available and has a confidence level that is
// high enough.
//
if(currentProvider != Provider.NONE)
return currentProvider;
//
// Case: The current provider should be used before the preselected provider,
// but the current provider is not available or does not have a confidence
// level that is high enough. The preselected provider is available and
// has a confidence level that is high enough.
//
if(preselectedProvider != Provider.NONE)
return preselectedProvider;
// When there is an app-wide preselected provider, and it has a confidence level that is high enough, we return it:
return this.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.ConfigurationData.App.PreselectedProvider && x.UsedLLMProvider.GetConfidence(this).Level >= minimumLevel) ?? Provider.NONE;
2024-09-04 13:44:23 +00:00
}
2024-09-08 19:01:51 +00:00
[SuppressMessage("Usage", "MWAIS0001:Direct access to `Providers` is not allowed")]
public Provider GetChatProviderForLoadedChat(string? chatProviderId = null)
{
var minimumLevel = this.GetMinimumConfidenceLevel(Tools.Components.CHAT);
bool IsSelectableProvider(Provider provider) =>
provider != Provider.NONE
&& provider.UsedLLMProvider != LLMProviders.NONE
&& provider.UsedLLMProvider.GetConfidence(this).Level >= minimumLevel;
Provider? FindProviderById(string? providerId)
{
if (string.IsNullOrWhiteSpace(providerId))
return null;
var provider = this.ConfigurationData.Providers.FirstOrDefault(x => x.Id == providerId);
return provider is not null && IsSelectableProvider(provider) ? provider : null;
}
var chatProvider = FindProviderById(chatProviderId);
if (chatProvider is not null)
return chatProvider;
var defaultChatProvider = this.ConfigurationData.Chat.PreselectOptions
? FindProviderById(this.ConfigurationData.Chat.PreselectedProvider)
: null;
if (defaultChatProvider is not null)
return defaultChatProvider;
var defaultAppProvider = FindProviderById(this.ConfigurationData.App.PreselectedProvider);
if (defaultAppProvider is not null)
return defaultAppProvider;
var selectableProviders = this.ConfigurationData.Providers.Where(IsSelectableProvider).ToList();
return selectableProviders.Count == 1 ? selectableProviders[0] : Provider.NONE;
}
2024-09-08 19:01:51 +00:00
public Profile GetPreselectedProfile(Tools.Components component)
{
var preselection = component.GetProfilePreselection(this);
if (preselection.DoNotPreselectProfile)
return Profile.NO_PROFILE;
if (preselection.UseSpecificProfile)
{
var componentProfile = this.ConfigurationData.Profiles.FirstOrDefault(x => x.Id.Equals(preselection.SpecificProfileId, StringComparison.OrdinalIgnoreCase));
return componentProfile ?? Profile.NO_PROFILE;
}
var appPreselection = ProfilePreselection.FromStoredValue(this.ConfigurationData.App.PreselectedProfile);
if (appPreselection.DoNotPreselectProfile || !appPreselection.UseSpecificProfile)
return Profile.NO_PROFILE;
var appProfile = this.ConfigurationData.Profiles.FirstOrDefault(x => x.Id.Equals(appPreselection.SpecificProfileId, StringComparison.OrdinalIgnoreCase));
return appProfile ?? Profile.NO_PROFILE;
}
public Profile GetAppPreselectedProfile()
{
var appPreselection = ProfilePreselection.FromStoredValue(this.ConfigurationData.App.PreselectedProfile);
if (appPreselection.DoNotPreselectProfile || !appPreselection.UseSpecificProfile)
return Profile.NO_PROFILE;
var appProfile = this.ConfigurationData.Profiles.FirstOrDefault(x => x.Id.Equals(appPreselection.SpecificProfileId, StringComparison.OrdinalIgnoreCase));
return appProfile ?? Profile.NO_PROFILE;
2024-09-08 19:01:51 +00:00
}
2025-05-24 10:27:00 +00:00
public ChatTemplate GetPreselectedChatTemplate(Tools.Components component)
{
var preselection = component.PreselectedChatTemplate(this);
if (preselection != ChatTemplate.NO_CHAT_TEMPLATE)
2025-05-24 10:27:00 +00:00
return preselection;
2026-01-09 11:45:21 +00:00
preselection = this.ConfigurationData.ChatTemplates.FirstOrDefault(x => x.Id.Equals(this.ConfigurationData.App.PreselectedChatTemplate, StringComparison.OrdinalIgnoreCase));
return preselection ?? ChatTemplate.NO_CHAT_TEMPLATE;
2025-05-24 10:27:00 +00:00
}
2024-09-11 21:08:02 +00:00
public HashSet<string> GetDefaultToolIds(AIStudio.Tools.Components component)
{
var key = component.ToString();
if (this.ConfigurationData.Tools.DefaultToolIdsByComponent.TryGetValue(key, out var toolIds))
return ToolSelectionRules.NormalizeSelection(toolIds);
return [];
}
2026-06-11 14:25:26 +00:00
public HashSet<string> FilterToolIdsForProvider(AIStudio.Settings.Provider provider, IEnumerable<string> selectedToolIds)
{
var toolCallingAvailability = provider.GetToolCallingAvailability();
if (!toolCallingAvailability.IsAvailable)
return [];
var modelCapabilities = provider.GetModelCapabilities();
var supportsRequiredApis =
modelCapabilities.Contains(Capability.CHAT_COMPLETION_API) ||
modelCapabilities.Contains(Capability.RESPONSES_API);
if (!supportsRequiredApis || !modelCapabilities.Contains(Capability.FUNCTION_CALLING))
return [];
var providerConfidence = provider.UsedLLMProvider.GetConfidence(this).Level;
var filtered = ToolSelectionRules.NormalizeSelection(selectedToolIds);
var changed = true;
while (changed)
{
changed = false;
foreach (var toolId in filtered.ToList())
{
var minimumToolConfidence = this.GetMinimumProviderConfidenceForTool(toolId);
if (ToolSelectionRules.IsProviderConfidenceAllowed(providerConfidence, minimumToolConfidence))
continue;
filtered.Remove(toolId);
changed = true;
}
if (filtered.Contains(ToolSelectionRules.WEB_SEARCH_TOOL_ID) && !filtered.Contains(ToolSelectionRules.READ_WEB_PAGE_TOOL_ID))
{
filtered.Remove(ToolSelectionRules.WEB_SEARCH_TOOL_ID);
changed = true;
}
}
return filtered;
}
public bool IsToolSelectionVisible(AIStudio.Tools.Components component) => component switch
{
AIStudio.Tools.Components.CHAT => true,
_ => this.ConfigurationData.Tools.VisibleToolSelectionComponents.Contains(component.ToString()),
};
public void SetToolSelectionVisibility(AIStudio.Tools.Components component, bool isVisible)
{
if (component is AIStudio.Tools.Components.CHAT)
return;
var key = component.ToString();
if (isVisible)
this.ConfigurationData.Tools.VisibleToolSelectionComponents.Add(key);
else
this.ConfigurationData.Tools.VisibleToolSelectionComponents.Remove(key);
}
2026-06-11 14:25:26 +00:00
public ToolMinimumProviderConfidenceResolution GetMinimumProviderConfidenceResolutionForTool(string toolId)
{
2026-06-11 14:25:26 +00:00
if (ManagedConfiguration.TryGet(x => x.Tools, x => x.MinimumProviderConfidenceByToolId, out var configMeta) && configMeta.IsLocked)
{
var managedValues = configMeta.GetValue();
if (managedValues.TryGetValue(toolId, out var configuredManagedLevel) &&
Enum.TryParse<ConfidenceLevel>(configuredManagedLevel, true, out var managedConfidenceLevel) &&
managedConfidenceLevel is not ConfidenceLevel.UNKNOWN)
{
return new(managedConfidenceLevel, "managed config");
}
}
if (this.ConfigurationData.Tools.MinimumProviderConfidenceByToolId.TryGetValue(toolId, out var configuredLevel) &&
Enum.TryParse<ConfidenceLevel>(configuredLevel, true, out var confidenceLevel) &&
confidenceLevel is not ConfidenceLevel.UNKNOWN)
{
2026-06-11 14:25:26 +00:00
return new(confidenceLevel, "stored override");
}
2026-06-11 14:25:26 +00:00
return new(ToolSelectionRules.GetDefaultMinimumProviderConfidence(toolId), "default fallback");
}
2026-06-11 14:25:26 +00:00
public ConfidenceLevel GetMinimumProviderConfidenceForTool(string toolId) => this.GetMinimumProviderConfidenceResolutionForTool(toolId).ConfidenceLevel;
public void SetMinimumProviderConfidenceForTool(string toolId, ConfidenceLevel confidenceLevel)
{
var defaultLevel = ToolSelectionRules.GetDefaultMinimumProviderConfidence(toolId);
if (confidenceLevel == defaultLevel)
{
this.ConfigurationData.Tools.MinimumProviderConfidenceByToolId.Remove(toolId);
return;
}
this.ConfigurationData.Tools.MinimumProviderConfidenceByToolId[toolId] = confidenceLevel.ToString();
}
public ConfidenceLevel GetConfiguredConfidenceLevel(LLMProviders llmProvider)
2024-09-11 21:08:02 +00:00
{
if(llmProvider is LLMProviders.NONE)
2024-09-11 21:08:02 +00:00
return ConfidenceLevel.NONE;
switch (this.ConfigurationData.LLMProviders.ConfidenceScheme)
{
2025-02-27 11:43:19 +00:00
case ConfidenceSchemes.TRUST_ALL:
return llmProvider switch
{
LLMProviders.SELF_HOSTED => ConfidenceLevel.HIGH,
_ => ConfidenceLevel.MEDIUM,
};
2024-09-11 21:08:02 +00:00
case ConfidenceSchemes.TRUST_USA_EUROPE:
return llmProvider switch
2024-09-11 21:08:02 +00:00
{
LLMProviders.SELF_HOSTED => ConfidenceLevel.HIGH,
2025-02-27 11:43:19 +00:00
LLMProviders.DEEP_SEEK => ConfidenceLevel.LOW,
2024-09-11 21:08:02 +00:00
_ => ConfidenceLevel.MEDIUM,
};
case ConfidenceSchemes.TRUST_USA:
return llmProvider switch
2024-09-11 21:08:02 +00:00
{
LLMProviders.SELF_HOSTED => ConfidenceLevel.HIGH,
LLMProviders.MISTRAL => ConfidenceLevel.LOW,
2025-02-27 11:43:19 +00:00
LLMProviders.HELMHOLTZ => ConfidenceLevel.LOW,
LLMProviders.GWDG => ConfidenceLevel.LOW,
LLMProviders.DEEP_SEEK => ConfidenceLevel.LOW,
2024-09-11 21:08:02 +00:00
_ => ConfidenceLevel.MEDIUM,
};
case ConfidenceSchemes.TRUST_EUROPE:
return llmProvider switch
2024-09-11 21:08:02 +00:00
{
LLMProviders.SELF_HOSTED => ConfidenceLevel.HIGH,
LLMProviders.MISTRAL => ConfidenceLevel.MEDIUM,
2025-02-27 11:43:19 +00:00
LLMProviders.HELMHOLTZ => ConfidenceLevel.MEDIUM,
LLMProviders.GWDG => ConfidenceLevel.MEDIUM,
_ => ConfidenceLevel.LOW,
};
case ConfidenceSchemes.TRUST_ASIA:
return llmProvider switch
{
LLMProviders.SELF_HOSTED => ConfidenceLevel.HIGH,
LLMProviders.DEEP_SEEK => ConfidenceLevel.MEDIUM,
2024-09-11 21:08:02 +00:00
_ => ConfidenceLevel.LOW,
};
case ConfidenceSchemes.LOCAL_TRUST_ONLY:
return llmProvider switch
2024-09-11 21:08:02 +00:00
{
LLMProviders.SELF_HOSTED => ConfidenceLevel.HIGH,
2024-09-11 21:08:02 +00:00
_ => ConfidenceLevel.VERY_LOW,
};
case ConfidenceSchemes.CUSTOM:
return this.ConfigurationData.LLMProviders.CustomConfidenceScheme.GetValueOrDefault(llmProvider, ConfidenceLevel.UNKNOWN);
2024-09-11 21:08:02 +00:00
default:
return ConfidenceLevel.UNKNOWN;
}
}
public static string ToSettingName<TIn, TOut>(Expression<Func<TIn, TOut>> propertyExpression)
{
MemberExpression? memberExpr;
// Handle the case where the expression is a unary expression (e.g., when using Convert):
if (propertyExpression.Body is UnaryExpression { NodeType: ExpressionType.Convert } unaryExpr)
memberExpr = unaryExpr.Operand as MemberExpression;
else
memberExpr = propertyExpression.Body as MemberExpression;
if (memberExpr is null)
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}";
}
}