mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-05-21 20:12:14 +00:00
Merge b6683b8d42 into cef1c99765
This commit is contained in:
commit
0cad3e685c
@ -260,6 +260,10 @@ CONFIG["SETTINGS"] = {}
|
|||||||
-- Examples are: "CmdOrControl+Shift+D", "Alt+F9", "F8"
|
-- Examples are: "CmdOrControl+Shift+D", "Alt+F9", "F8"
|
||||||
-- CONFIG["SETTINGS"]["DataApp.ShortcutVoiceRecording"] = "CmdOrControl+1"
|
-- CONFIG["SETTINGS"]["DataApp.ShortcutVoiceRecording"] = "CmdOrControl+1"
|
||||||
|
|
||||||
|
-- Configure the HTTP timeout for requests to LLM providers, in seconds.
|
||||||
|
-- The default is 3600 (1 hour).
|
||||||
|
-- CONFIG["SETTINGS"]["DataApp.ProviderHttpTimeoutSeconds"] = 3600
|
||||||
|
|
||||||
-- Example chat templates for this configuration:
|
-- Example chat templates for this configuration:
|
||||||
CONFIG["CHAT_TEMPLATES"] = {}
|
CONFIG["CHAT_TEMPLATES"] = {}
|
||||||
|
|
||||||
|
|||||||
@ -24,7 +24,10 @@ namespace AIStudio.Provider;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BaseProvider : IProvider, ISecretId
|
public abstract class BaseProvider : IProvider, ISecretId
|
||||||
{
|
{
|
||||||
|
private const int DEFAULT_HTTP_TIMEOUT_SECONDS = 3600;
|
||||||
|
|
||||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(BaseProvider).Namespace, nameof(BaseProvider));
|
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(BaseProvider).Namespace, nameof(BaseProvider));
|
||||||
|
private static readonly SettingsManager SETTINGS_MANAGER = Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The HTTP client to use it for all requests.
|
/// The HTTP client to use it for all requests.
|
||||||
@ -74,6 +77,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
|
|
||||||
// Set the base URL:
|
// Set the base URL:
|
||||||
this.HttpClient.BaseAddress = new(url);
|
this.HttpClient.BaseAddress = new(url);
|
||||||
|
this.HttpClient.Timeout = GetProviderHttpTimeout();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Handling of IProvider, which all providers must implement
|
#region Handling of IProvider, which all providers must implement
|
||||||
@ -136,6 +140,58 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
|
|
||||||
protected static ModelLoadResult FailedModelLoadResult(ModelLoadFailureReason failureReason, string? technicalDetails = null) => ModelLoadResult.Failure(failureReason, technicalDetails);
|
protected static ModelLoadResult FailedModelLoadResult(ModelLoadFailureReason failureReason, string? technicalDetails = null) => ModelLoadResult.Failure(failureReason, technicalDetails);
|
||||||
|
|
||||||
|
protected bool IsTimeoutException(Exception exception, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (exception is TimeoutException)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (exception is OperationCanceledException)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return exception.InnerException is not null && this.IsTimeoutException(exception.InnerException, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Task SendTimeoutError(string action) => MessageBus.INSTANCE.SendError(new(
|
||||||
|
Icons.Material.Filled.HourglassTop,
|
||||||
|
string.Format(
|
||||||
|
TB("The request to the LLM provider '{0}' (type={1}) timed out after {2} while {3}. Please try again or check whether the provider is still responding."),
|
||||||
|
this.InstanceName,
|
||||||
|
this.Provider,
|
||||||
|
GetProviderHttpTimeoutDescription(),
|
||||||
|
action)));
|
||||||
|
|
||||||
|
private static TimeSpan GetProviderHttpTimeout()
|
||||||
|
{
|
||||||
|
var seconds = SETTINGS_MANAGER.ConfigurationData.App.ProviderHttpTimeoutSeconds;
|
||||||
|
if (seconds <= 0)
|
||||||
|
seconds = DEFAULT_HTTP_TIMEOUT_SECONDS;
|
||||||
|
|
||||||
|
return TimeSpan.FromSeconds(seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetProviderHttpTimeoutDescription()
|
||||||
|
{
|
||||||
|
var timeout = GetProviderHttpTimeout();
|
||||||
|
|
||||||
|
if (timeout.TotalHours >= 1 && timeout.TotalMinutes % 60 == 0)
|
||||||
|
{
|
||||||
|
var hours = (int)timeout.TotalHours;
|
||||||
|
return hours == 1 ? "1 hour" : $"{hours} hours";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout.TotalMinutes >= 1 && timeout.TotalSeconds % 60 == 0)
|
||||||
|
{
|
||||||
|
var minutes = (int)timeout.TotalMinutes;
|
||||||
|
return minutes == 1 ? "1 minute" : $"{minutes} minutes";
|
||||||
|
}
|
||||||
|
|
||||||
|
var seconds = (int)timeout.TotalSeconds;
|
||||||
|
return seconds == 1 ? "1 second" : $"{seconds} seconds";
|
||||||
|
}
|
||||||
|
|
||||||
protected async Task<string?> GetModelLoadingSecretKey(SecretStoreType storeType, string? apiKeyProvisional = null, bool isTryingSecret = false) => apiKeyProvisional switch
|
protected async Task<string?> GetModelLoadingSecretKey(SecretStoreType storeType, string? apiKeyProvisional = null, bool isTryingSecret = false) => apiKeyProvisional switch
|
||||||
{
|
{
|
||||||
not null => apiKeyProvisional,
|
not null => apiKeyProvisional,
|
||||||
@ -175,6 +231,8 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
else if (!string.IsNullOrWhiteSpace(secretKey))
|
else if (!string.IsNullOrWhiteSpace(secretKey))
|
||||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", secretKey);
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", secretKey);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
using var response = await this.HttpClient.SendAsync(request, token);
|
using var response = await this.HttpClient.SendAsync(request, token);
|
||||||
var responseBody = await response.Content.ReadAsStringAsync(token);
|
var responseBody = await response.Content.ReadAsStringAsync(token);
|
||||||
if (!response.IsSuccessStatusCode)
|
if (!response.IsSuccessStatusCode)
|
||||||
@ -196,6 +254,13 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
return FailedModelLoadResult(ModelLoadFailureReason.INVALID_RESPONSE, e.Message);
|
return FailedModelLoadResult(ModelLoadFailureReason.INVALID_RESPONSE, e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception e) when (this.IsTimeoutException(e, token))
|
||||||
|
{
|
||||||
|
await this.SendTimeoutError("loading the available models");
|
||||||
|
this.logger.LogError(e, "Timed out while loading models from provider '{ProviderInstanceName}' (provider={ProviderType}).", this.InstanceName, this.Provider);
|
||||||
|
return FailedModelLoadResult(ModelLoadFailureReason.PROVIDER_UNAVAILABLE, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends a request and handles rate limiting by exponential backoff.
|
/// Sends a request and handles rate limiting by exponential backoff.
|
||||||
@ -223,7 +288,18 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
// Please notice: We do not dispose the response here. The caller is responsible
|
// Please notice: We do not dispose the response here. The caller is responsible
|
||||||
// for disposing the response object. This is important because the response
|
// for disposing the response object. This is important because the response
|
||||||
// object is used to read the stream.
|
// object is used to read the stream.
|
||||||
var nextResponse = await this.HttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, token);
|
HttpResponseMessage nextResponse;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
nextResponse = await this.HttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, token);
|
||||||
|
}
|
||||||
|
catch (Exception e) when (this.IsTimeoutException(e, token))
|
||||||
|
{
|
||||||
|
await this.SendTimeoutError("waiting for the chat response");
|
||||||
|
this.logger.LogError(e, "Timed out while sending a streaming request to provider '{ProviderInstanceName}' (provider={ProviderType}).", this.InstanceName, this.Provider);
|
||||||
|
return new HttpRateLimitedStreamResult(false, true, e.Message, response);
|
||||||
|
}
|
||||||
|
|
||||||
if (nextResponse.IsSuccessStatusCode)
|
if (nextResponse.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
response = nextResponse;
|
response = nextResponse;
|
||||||
@ -340,10 +416,22 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
streamReader = new StreamReader(providerStream);
|
streamReader = new StreamReader(providerStream);
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
this.logger.LogWarning("The user canceled the chat completion request for {ProviderName} '{ProviderInstanceName}' before the response stream was opened.", providerName, this.InstanceName);
|
||||||
|
}
|
||||||
|
else if (this.IsTimeoutException(e, token))
|
||||||
|
{
|
||||||
|
await this.SendTimeoutError("opening the chat response stream");
|
||||||
|
this.logger.LogError(e, "Timed out while opening the chat completion stream from {ProviderName} '{ProviderInstanceName}'.", providerName, this.InstanceName);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Stream, string.Format(TB("Tried to communicate with the LLM provider '{0}'. There were some problems with the request. The provider message is: '{1}'"), this.InstanceName, e.Message)));
|
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Stream, string.Format(TB("Tried to communicate with the LLM provider '{0}'. There were some problems with the request. The provider message is: '{1}'"), this.InstanceName, e.Message)));
|
||||||
this.logger.LogError($"Failed to stream chat completion from {providerName} '{this.InstanceName}': {e.Message}");
|
this.logger.LogError($"Failed to stream chat completion from {providerName} '{this.InstanceName}': {e.Message}");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (streamReader is null)
|
if (streamReader is null)
|
||||||
yield break;
|
yield break;
|
||||||
@ -382,9 +470,22 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
line = await streamReader.ReadLineAsync(token);
|
line = await streamReader.ReadLineAsync(token);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
this.logger.LogWarning("The user canceled the chat completion stream for {ProviderName} '{ProviderInstanceName}' while reading the next chunk.", providerName, this.InstanceName);
|
||||||
|
}
|
||||||
|
else if (this.IsTimeoutException(e, token))
|
||||||
|
{
|
||||||
|
await this.SendTimeoutError("reading the chat response stream");
|
||||||
|
this.logger.LogError(e, "Timed out while reading the chat stream from {ProviderName} '{ProviderInstanceName}'.", providerName, this.InstanceName);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Stream, string.Format(TB("Tried to stream the LLM provider '{0}' answer. Was not able to read the stream. The message is: '{1}'"), this.InstanceName, e.Message)));
|
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Stream, string.Format(TB("Tried to stream the LLM provider '{0}' answer. Was not able to read the stream. The message is: '{1}'"), this.InstanceName, e.Message)));
|
||||||
this.logger.LogError($"Failed to read the stream from {providerName} '{this.InstanceName}': {e.Message}");
|
this.logger.LogError($"Failed to read the stream from {providerName} '{this.InstanceName}': {e.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -504,10 +605,22 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
streamReader = new StreamReader(providerStream);
|
streamReader = new StreamReader(providerStream);
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
this.logger.LogWarning("The user canceled the responses request for {ProviderName} '{ProviderInstanceName}' before the response stream was opened.", providerName, this.InstanceName);
|
||||||
|
}
|
||||||
|
else if (this.IsTimeoutException(e, token))
|
||||||
|
{
|
||||||
|
await this.SendTimeoutError("opening the chat response stream");
|
||||||
|
this.logger.LogError(e, "Timed out while opening the responses stream from {ProviderName} '{ProviderInstanceName}'.", providerName, this.InstanceName);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Stream, string.Format(TB("Tried to communicate with the LLM provider '{0}'. There were some problems with the request. The provider message is: '{1}'"), this.InstanceName, e.Message)));
|
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Stream, string.Format(TB("Tried to communicate with the LLM provider '{0}'. There were some problems with the request. The provider message is: '{1}'"), this.InstanceName, e.Message)));
|
||||||
this.logger.LogError($"Failed to stream responses from {providerName} '{this.InstanceName}': {e.Message}");
|
this.logger.LogError($"Failed to stream responses from {providerName} '{this.InstanceName}': {e.Message}");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (streamReader is null)
|
if (streamReader is null)
|
||||||
yield break;
|
yield break;
|
||||||
@ -546,9 +659,22 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
line = await streamReader.ReadLineAsync(token);
|
line = await streamReader.ReadLineAsync(token);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
this.logger.LogWarning("The user canceled the responses stream for {ProviderName} '{ProviderInstanceName}' while reading the next chunk.", providerName, this.InstanceName);
|
||||||
|
}
|
||||||
|
else if (this.IsTimeoutException(e, token))
|
||||||
|
{
|
||||||
|
await this.SendTimeoutError("reading the chat response stream");
|
||||||
|
this.logger.LogError(e, "Timed out while reading the responses stream from {ProviderName} '{ProviderInstanceName}'.", providerName, this.InstanceName);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Stream, string.Format(TB("Tried to stream the LLM provider '{0}' answer. Was not able to read the stream. The message is: '{1}'"), this.InstanceName, e.Message)));
|
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Stream, string.Format(TB("Tried to stream the LLM provider '{0}' answer. Was not able to read the stream. The message is: '{1}'"), this.InstanceName, e.Message)));
|
||||||
this.logger.LogError($"Failed to read the stream from {providerName} '{this.InstanceName}': {e.Message}");
|
this.logger.LogError($"Failed to read the stream from {providerName} '{this.InstanceName}': {e.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -784,6 +910,9 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
if (this.IsTimeoutException(e, token))
|
||||||
|
await this.SendTimeoutError("transcribing audio");
|
||||||
|
|
||||||
this.logger.LogError("Failed to perform transcription request: '{Message}'.", e.Message);
|
this.logger.LogError("Failed to perform transcription request: '{Message}'.", e.Message);
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
@ -859,6 +988,9 @@ public abstract class BaseProvider : IProvider, ISecretId
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
if (this.IsTimeoutException(e, token))
|
||||||
|
await this.SendTimeoutError("creating embeddings");
|
||||||
|
|
||||||
this.logger.LogError("Failed to perform embedding request: '{Message}'.", e.Message);
|
this.logger.LogError("Failed to perform embedding request: '{Message}'.", e.Message);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -135,6 +135,9 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, "https://gener
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
if (this.IsTimeoutException(e, token))
|
||||||
|
await this.SendTimeoutError("creating embeddings");
|
||||||
|
|
||||||
LOGGER.LogError("Failed to perform embedding request: '{Message}'.", e.Message);
|
LOGGER.LogError("Failed to perform embedding request: '{Message}'.", e.Message);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -125,6 +125,8 @@ public sealed class ProviderHelmholtz() : BaseProvider(LLMProviders.HELMHOLTZ, "
|
|||||||
if (string.IsNullOrWhiteSpace(secretKey))
|
if (string.IsNullOrWhiteSpace(secretKey))
|
||||||
return FailedModelLoadResult(ModelLoadFailureReason.INVALID_OR_MISSING_API_KEY, "No API key available for model loading.");
|
return FailedModelLoadResult(ModelLoadFailureReason.INVALID_OR_MISSING_API_KEY, "No API key available for model loading.");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
using var request = new HttpRequestMessage(HttpMethod.Get, "models");
|
using var request = new HttpRequestMessage(HttpMethod.Get, "models");
|
||||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", secretKey);
|
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", secretKey);
|
||||||
|
|
||||||
@ -152,4 +154,11 @@ public sealed class ProviderHelmholtz() : BaseProvider(LLMProviders.HELMHOLTZ, "
|
|||||||
return FailedModelLoadResult(ModelLoadFailureReason.UNKNOWN, e.Message);
|
return FailedModelLoadResult(ModelLoadFailureReason.UNKNOWN, e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception e) when (this.IsTimeoutException(e, token))
|
||||||
|
{
|
||||||
|
await this.SendTimeoutError("loading the available models");
|
||||||
|
LOGGER.LogError(e, "Timed out while loading models from Helmholtz provider '{ProviderInstanceName}'.", this.InstanceName);
|
||||||
|
return FailedModelLoadResult(ModelLoadFailureReason.PROVIDER_UNAVAILABLE, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -173,6 +173,8 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide
|
|||||||
{
|
{
|
||||||
var secretKey = await this.GetModelLoadingSecretKey(storeType, apiKeyProvisional, true);
|
var secretKey = await this.GetModelLoadingSecretKey(storeType, apiKeyProvisional, true);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
using var lmStudioRequest = new HttpRequestMessage(HttpMethod.Get, "models");
|
using var lmStudioRequest = new HttpRequestMessage(HttpMethod.Get, "models");
|
||||||
if(secretKey is not null)
|
if(secretKey is not null)
|
||||||
lmStudioRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", secretKey);
|
lmStudioRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", secretKey);
|
||||||
@ -187,4 +189,11 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide
|
|||||||
filterPhrases.All( filter => model.Id.Contains(filter, StringComparison.InvariantCulture)))
|
filterPhrases.All( filter => model.Id.Contains(filter, StringComparison.InvariantCulture)))
|
||||||
.Select(n => new Provider.Model(n.Id, null)));
|
.Select(n => new Provider.Model(n.Id, null)));
|
||||||
}
|
}
|
||||||
|
catch (Exception e) when (this.IsTimeoutException(e, token))
|
||||||
|
{
|
||||||
|
await this.SendTimeoutError("loading the available models");
|
||||||
|
LOGGER.LogError(e, "Timed out while loading models from self-hosted provider '{ProviderInstanceName}'.", this.InstanceName);
|
||||||
|
return FailedModelLoadResult(ModelLoadFailureReason.PROVIDER_UNAVAILABLE, e.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -94,6 +94,11 @@ public sealed class DataApp(Expression<Func<Data, DataApp>>? configSelection = n
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string ShortcutVoiceRecording { get; set; } = ManagedConfiguration.Register(configSelection, n => n.ShortcutVoiceRecording, string.Empty);
|
public string ShortcutVoiceRecording { get; set; } = ManagedConfiguration.Register(configSelection, n => n.ShortcutVoiceRecording, string.Empty);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The HTTP timeout in seconds for requests to LLM providers.
|
||||||
|
/// </summary>
|
||||||
|
public int ProviderHttpTimeoutSeconds { get; set; } = ManagedConfiguration.Register(configSelection, n => n.ProviderHttpTimeoutSeconds, 3600);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Should the user be allowed to add providers?
|
/// Should the user be allowed to add providers?
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -172,6 +172,9 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT
|
|||||||
// Config: global voice recording shortcut
|
// Config: global voice recording shortcut
|
||||||
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.ShortcutVoiceRecording, this.Id, settingsTable, dryRun);
|
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.ShortcutVoiceRecording, this.Id, settingsTable, dryRun);
|
||||||
|
|
||||||
|
// Config: timeout for HTTP requests to providers
|
||||||
|
ManagedConfiguration.TryProcessConfiguration(x => x.App, x => x.ProviderHttpTimeoutSeconds, this.Id, settingsTable, dryRun);
|
||||||
|
|
||||||
// Handle configured LLM providers:
|
// Handle configured LLM providers:
|
||||||
PluginConfigurationObject.TryParse(PluginConfigurationObjectType.LLM_PROVIDER, x => x.Providers, x => x.NextProviderNum, mainTable, this.Id, ref this.configObjects, dryRun);
|
PluginConfigurationObject.TryParse(PluginConfigurationObjectType.LLM_PROVIDER, x => x.Providers, x => x.NextProviderNum, mainTable, this.Id, ref this.configObjects, dryRun);
|
||||||
|
|
||||||
|
|||||||
@ -245,6 +245,10 @@ public static partial class PluginFactory
|
|||||||
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.ShortcutVoiceRecording, AVAILABLE_PLUGINS))
|
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.ShortcutVoiceRecording, AVAILABLE_PLUGINS))
|
||||||
wasConfigurationChanged = true;
|
wasConfigurationChanged = true;
|
||||||
|
|
||||||
|
// Check for the provider HTTP timeout:
|
||||||
|
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.App, x => x.ProviderHttpTimeoutSeconds, AVAILABLE_PLUGINS))
|
||||||
|
wasConfigurationChanged = true;
|
||||||
|
|
||||||
// Check if audit is required before it can be activated
|
// Check if audit is required before it can be activated
|
||||||
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.AssistantPluginAudit, x => x.RequireAuditBeforeActivation, AVAILABLE_PLUGINS))
|
if(ManagedConfiguration.IsConfigurationLeftOver(x => x.AssistantPluginAudit, x => x.RequireAuditBeforeActivation, AVAILABLE_PLUGINS))
|
||||||
wasConfigurationChanged = true;
|
wasConfigurationChanged = true;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user