mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-06-12 03:36:27 +00:00
Fixed issues with the DI system and singletons (#802)
Some checks are pending
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Publish release (push) Blocked by required conditions
Some checks are pending
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Publish release (push) Blocked by required conditions
This commit is contained in:
parent
1c2d243c1f
commit
c07a5227dc
@ -94,6 +94,8 @@ public sealed record ChatThread
|
||||
/// <returns>The prepared system prompt.</returns>
|
||||
public string PrepareSystemPrompt(SettingsManager settingsManager)
|
||||
{
|
||||
this.allowProfile = true;
|
||||
|
||||
//
|
||||
// Use the information from the chat template, if provided. Otherwise, use the default system prompt
|
||||
//
|
||||
@ -111,8 +113,8 @@ public sealed record ChatThread
|
||||
systemPromptTextWithChatTemplate = this.SystemPrompt;
|
||||
else
|
||||
{
|
||||
var chatTemplate = settingsManager.ConfigurationData.ChatTemplates.FirstOrDefault(x => x.Id == this.SelectedChatTemplate);
|
||||
if(chatTemplate == null)
|
||||
var chatTemplate = settingsManager.GetChatTemplateById(this.SelectedChatTemplate);
|
||||
if(chatTemplate == ChatTemplate.NO_CHAT_TEMPLATE)
|
||||
systemPromptTextWithChatTemplate = this.SystemPrompt;
|
||||
else
|
||||
{
|
||||
@ -168,8 +170,8 @@ public sealed record ChatThread
|
||||
systemPromptText = systemPromptWithAugmentedData;
|
||||
else
|
||||
{
|
||||
var profile = settingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == this.SelectedProfile);
|
||||
if(profile is null)
|
||||
var profile = settingsManager.GetProfileById(this.SelectedProfile);
|
||||
if(profile == Profile.NO_PROFILE)
|
||||
systemPromptText = systemPromptWithAugmentedData;
|
||||
else
|
||||
{
|
||||
|
||||
@ -101,7 +101,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
// Apply the filters for the message bus:
|
||||
this.ApplyFilters([], [ Event.HAS_CHAT_UNSAVED_CHANGES, Event.RESET_CHAT_STATE, Event.CHAT_STREAMING_DONE, Event.AI_JOB_CHANGED, Event.AI_JOB_FINISHED, Event.CHAT_GENERATION_CHANGED, Event.WORKSPACE_RENAMED ]);
|
||||
this.ApplyFilters([], [ Event.HAS_CHAT_UNSAVED_CHANGES, Event.RESET_CHAT_STATE, Event.CHAT_STREAMING_DONE, Event.AI_JOB_CHANGED, Event.AI_JOB_FINISHED, Event.CHAT_GENERATION_CHANGED, Event.WORKSPACE_RENAMED, Event.CONFIGURATION_CHANGED ]);
|
||||
|
||||
// Configure the spellchecking for the user input:
|
||||
this.SettingsManager.InjectSpellchecking(USER_INPUT_ATTRIBUTES);
|
||||
@ -470,7 +470,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
|
||||
private async Task ProfileWasChanged(Profile profile)
|
||||
{
|
||||
this.currentProfile = profile;
|
||||
this.currentProfile = this.SettingsManager.GetProfileById(profile.Id);
|
||||
if(this.ChatThread is null)
|
||||
return;
|
||||
|
||||
@ -484,7 +484,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
|
||||
private async Task ChatTemplateWasChanged(ChatTemplate chatTemplate)
|
||||
{
|
||||
this.currentChatTemplate = chatTemplate;
|
||||
this.currentChatTemplate = this.SettingsManager.GetChatTemplateById(chatTemplate.Id);
|
||||
if(!string.IsNullOrWhiteSpace(this.currentChatTemplate.PredefinedUserPrompt))
|
||||
this.ComposerState.SetSystemInput(this.currentChatTemplate.PredefinedUserPrompt);
|
||||
|
||||
@ -497,6 +497,12 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
await this.StartNewChat(true);
|
||||
}
|
||||
|
||||
private void RefreshCurrentProfileAndChatTemplate()
|
||||
{
|
||||
this.currentProfile = this.SettingsManager.GetProfileById(this.currentProfile.Id);
|
||||
this.currentChatTemplate = this.SettingsManager.GetChatTemplateById(this.currentChatTemplate.Id);
|
||||
}
|
||||
|
||||
private IReadOnlyList<DataSourceAgentSelected> GetAgentSelectedDataSources()
|
||||
{
|
||||
if (this.ChatThread is null)
|
||||
@ -601,7 +607,9 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
|
||||
if(!this.ChatThread.IsLLMProviderAllowed(this.Provider))
|
||||
return;
|
||||
|
||||
|
||||
this.RefreshCurrentProfileAndChatTemplate();
|
||||
|
||||
// Blur the focus away from the input field to be able to clear it:
|
||||
await this.inputField.BlurAsync();
|
||||
|
||||
@ -795,6 +803,7 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
//
|
||||
this.hasUnsavedChanges = false;
|
||||
this.ComposerState.Clear();
|
||||
this.RefreshCurrentProfileAndChatTemplate();
|
||||
|
||||
//
|
||||
// Reset the LLM provider considering the user's settings:
|
||||
@ -967,14 +976,11 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
|
||||
// Try to select the profile:
|
||||
if (!string.IsNullOrWhiteSpace(chatProfile))
|
||||
this.currentProfile = this.SettingsManager.ConfigurationData.Profiles.FirstOrDefault(x => x.Id == chatProfile) ?? Profile.NO_PROFILE;
|
||||
this.currentProfile = this.SettingsManager.GetProfileById(chatProfile);
|
||||
|
||||
// Try to select the chat template:
|
||||
if (!string.IsNullOrWhiteSpace(chatChatTemplate))
|
||||
{
|
||||
var selectedTemplate = this.SettingsManager.ConfigurationData.ChatTemplates.FirstOrDefault(x => x.Id == chatChatTemplate);
|
||||
this.currentChatTemplate = selectedTemplate ?? ChatTemplate.NO_CHAT_TEMPLATE;
|
||||
}
|
||||
this.currentChatTemplate = this.SettingsManager.GetChatTemplateById(chatChatTemplate);
|
||||
}
|
||||
|
||||
private async Task ToggleWorkspaceOverlay()
|
||||
@ -1074,6 +1080,15 @@ public partial class ChatComponent : MSGComponentBase, IAsyncDisposable
|
||||
if (data is Guid workspaceId)
|
||||
await this.RefreshRenamedWorkspaceHeaderAsync(workspaceId);
|
||||
break;
|
||||
|
||||
case Event.CONFIGURATION_CHANGED:
|
||||
var previousChatTemplate = this.currentChatTemplate;
|
||||
this.RefreshCurrentProfileAndChatTemplate();
|
||||
if (!this.ComposerState.HasUserDraft && previousChatTemplate != this.currentChatTemplate)
|
||||
this.ComposerState.ApplyTemplate(this.currentChatTemplate);
|
||||
|
||||
this.StateHasChanged();
|
||||
break;
|
||||
|
||||
case Event.AI_JOB_CHANGED:
|
||||
case Event.AI_JOB_FINISHED:
|
||||
|
||||
@ -68,7 +68,7 @@ public sealed class ProviderAlibabaCloud() : BaseProvider(LLMProviders.ALIBABA_C
|
||||
/// <inhertidoc />
|
||||
public override async Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
return await this.PerformStandardTextEmbeddingRequest(requestedSecret, embeddingModel, token: token, texts: texts);
|
||||
}
|
||||
|
||||
|
||||
@ -27,7 +27,7 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, n
|
||||
public override async IAsyncEnumerable<ContentStreamChunk> StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
|
||||
{
|
||||
// Get the API key:
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER);
|
||||
if(!requestedSecret.Success)
|
||||
yield break;
|
||||
|
||||
@ -93,7 +93,7 @@ public sealed class ProviderAnthropic() : BaseProvider(LLMProviders.ANTHROPIC, n
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, "messages");
|
||||
|
||||
// Set the authorization header:
|
||||
request.Headers.Add("x-api-key", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Add("x-api-key", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
|
||||
// Set the Anthropic version:
|
||||
request.Headers.Add("anthropic-version", "2023-06-01");
|
||||
|
||||
@ -13,7 +13,6 @@ using AIStudio.Settings;
|
||||
using AIStudio.Tools.MIME;
|
||||
using AIStudio.Tools.PluginSystem;
|
||||
using AIStudio.Tools.Rust;
|
||||
using AIStudio.Tools.Services;
|
||||
|
||||
using Host = AIStudio.Provider.SelfHosted.Host;
|
||||
|
||||
@ -36,16 +35,6 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
/// </summary>
|
||||
private readonly ILogger logger;
|
||||
|
||||
static BaseProvider()
|
||||
{
|
||||
RUST_SERVICE = Program.RUST_SERVICE;
|
||||
ENCRYPTION = Program.ENCRYPTION;
|
||||
}
|
||||
|
||||
protected static readonly RustService RUST_SERVICE;
|
||||
|
||||
protected static readonly Encryption ENCRYPTION;
|
||||
|
||||
protected static readonly JsonSerializerOptions JSON_SERIALIZER_OPTIONS = new()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower,
|
||||
@ -161,9 +150,9 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
protected async Task<string?> GetModelLoadingSecretKey(SecretStoreType storeType, string? apiKeyProvisional = null, bool isTryingSecret = false) => apiKeyProvisional switch
|
||||
{
|
||||
not null => apiKeyProvisional,
|
||||
_ => await RUST_SERVICE.GetAPIKey(this, storeType, isTrying: isTryingSecret) switch
|
||||
_ => await Program.RUST_SERVICE.GetAPIKey(this, storeType, isTrying: isTryingSecret) switch
|
||||
{
|
||||
{ Success: true } result => await result.Secret.Decrypt(ENCRYPTION),
|
||||
{ Success: true } result => await result.Secret.Decrypt(Program.ENCRYPTION),
|
||||
_ => null,
|
||||
}
|
||||
};
|
||||
@ -981,7 +970,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
where TAnnotation : IAnnotationStreamLine
|
||||
{
|
||||
// Get the API key:
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, storeType, isTrying: isTryingSecret);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, storeType, isTrying: isTryingSecret);
|
||||
if(!requestedSecret.Success && !isTryingSecret)
|
||||
yield break;
|
||||
|
||||
@ -1005,7 +994,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
|
||||
// Set the authorization header:
|
||||
if (requestedSecret.Success)
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
|
||||
// Set provider-specific headers:
|
||||
headersAction?.Invoke(request.Headers);
|
||||
@ -1053,7 +1042,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
{
|
||||
case LLMProviders.SELF_HOSTED:
|
||||
if(requestedSecret.Success)
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
|
||||
break;
|
||||
|
||||
@ -1064,7 +1053,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
return TranscriptionResult.Failure();
|
||||
}
|
||||
|
||||
request.Headers.Add("Authorization", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Add("Authorization", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1074,7 +1063,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
return TranscriptionResult.Failure();
|
||||
}
|
||||
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1135,7 +1124,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
{
|
||||
case LLMProviders.SELF_HOSTED:
|
||||
if(requestedSecret.Success)
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
|
||||
break;
|
||||
|
||||
@ -1146,7 +1135,7 @@ public abstract class BaseProvider : IProvider, ISecretId
|
||||
return [];
|
||||
}
|
||||
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@ -63,7 +63,7 @@ public class ProviderFireworks() : BaseProvider(LLMProviders.FIREWORKS, new Uri(
|
||||
/// <inheritdoc />
|
||||
public override async Task<TranscriptionResult> TranscribeAudioAsync(Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, token: token);
|
||||
}
|
||||
|
||||
|
||||
@ -62,7 +62,7 @@ public sealed class ProviderGWDG() : BaseProvider(LLMProviders.GWDG, new Uri("ht
|
||||
/// <inheritdoc />
|
||||
public override async Task<TranscriptionResult> TranscribeAudioAsync(Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, token: token);
|
||||
}
|
||||
|
||||
|
||||
@ -71,7 +71,7 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, new Uri("https
|
||||
/// <inhertidoc />
|
||||
public override async Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
try
|
||||
{
|
||||
var modelName = embeddingModel.Id;
|
||||
@ -104,7 +104,7 @@ public class ProviderGoogle() : BaseProvider(LLMProviders.GOOGLE, new Uri("https
|
||||
var embeddingRequest = JsonSerializer.Serialize(payload, JSON_SERIALIZER_OPTIONS);
|
||||
var embedUrl = $"https://generativelanguage.googleapis.com/v1beta/models/{modelName}:embedContent";
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, embedUrl);
|
||||
request.Headers.Add("x-goog-api-key", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Add("x-goog-api-key", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
|
||||
// Set the content:
|
||||
request.Content = new StringContent(embeddingRequest, Encoding.UTF8, "application/json");
|
||||
|
||||
@ -70,7 +70,7 @@ public sealed class ProviderHelmholtz() : BaseProvider(LLMProviders.HELMHOLTZ, n
|
||||
/// <inhertidoc />
|
||||
public override async Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
return await this.PerformStandardTextEmbeddingRequest(requestedSecret, embeddingModel, token: token, texts: texts);
|
||||
}
|
||||
|
||||
|
||||
@ -69,14 +69,14 @@ public sealed class ProviderMistral() : BaseProvider(LLMProviders.MISTRAL, new U
|
||||
/// <inheritdoc />
|
||||
public override async Task<TranscriptionResult> TranscribeAudioAsync(Provider.Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, token: token);
|
||||
}
|
||||
|
||||
/// <inhertidoc />
|
||||
public override async Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Provider.Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
return await this.PerformStandardTextEmbeddingRequest(requestedSecret, embeddingModel, token: token, texts: texts);
|
||||
}
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur
|
||||
public override async IAsyncEnumerable<ContentStreamChunk> StreamChatCompletion(Model chatModel, ChatThread chatThread, SettingsManager settingsManager, [EnumeratorCancellation] CancellationToken token = default)
|
||||
{
|
||||
// Get the API key:
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.LLM_PROVIDER);
|
||||
if(!requestedSecret.Success)
|
||||
yield break;
|
||||
|
||||
@ -221,7 +221,7 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, requestPath);
|
||||
|
||||
// Set the authorization header:
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(ENCRYPTION));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await requestedSecret.Secret.Decrypt(Program.ENCRYPTION));
|
||||
|
||||
// Set the content:
|
||||
request.Content = new StringContent(openAIChatRequest, Encoding.UTF8, "application/json");
|
||||
@ -250,14 +250,14 @@ public sealed class ProviderOpenAI() : BaseProvider(LLMProviders.OPEN_AI, new Ur
|
||||
/// <inheritdoc />
|
||||
public override async Task<TranscriptionResult> TranscribeAudioAsync(Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER);
|
||||
return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, token: token);
|
||||
}
|
||||
|
||||
/// <inhertidoc />
|
||||
public override async Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
return await this.PerformStandardTextEmbeddingRequest(requestedSecret, embeddingModel, token: token, texts: texts);
|
||||
}
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ public sealed class ProviderOpenRouter() : BaseProvider(LLMProviders.OPEN_ROUTER
|
||||
/// <inhertidoc />
|
||||
public override async Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER);
|
||||
return await this.PerformStandardTextEmbeddingRequest(requestedSecret, embeddingModel, token: token, texts: texts);
|
||||
}
|
||||
|
||||
|
||||
@ -75,14 +75,14 @@ public sealed class ProviderSelfHosted(Host host, string hostname) : BaseProvide
|
||||
/// <inheritdoc />
|
||||
public override async Task<TranscriptionResult> TranscribeAudioAsync(Provider.Model transcriptionModel, string audioFilePath, SettingsManager settingsManager, CancellationToken token = default)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER, isTrying: true);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.TRANSCRIPTION_PROVIDER, isTrying: true);
|
||||
return await this.PerformStandardTranscriptionRequest(requestedSecret, transcriptionModel, audioFilePath, host, token);
|
||||
}
|
||||
|
||||
/// <inhertidoc />
|
||||
public override async Task<IReadOnlyList<IReadOnlyList<float>>> EmbedTextAsync(Provider.Model embeddingModel, SettingsManager settingsManager, CancellationToken token = default, params List<string> texts)
|
||||
{
|
||||
var requestedSecret = await RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER, isTrying: true);
|
||||
var requestedSecret = await Program.RUST_SERVICE.GetAPIKey(this, SecretStoreType.EMBEDDING_PROVIDER, isTrying: true);
|
||||
return await this.PerformStandardTextEmbeddingRequest(requestedSecret, embeddingModel, host, token: token, texts: texts);
|
||||
}
|
||||
|
||||
|
||||
@ -151,7 +151,7 @@ public record ConfigMeta<TClass, TValue> : ConfigMetaBase
|
||||
/// </summary>
|
||||
private void Reset()
|
||||
{
|
||||
var configInstance = this.ConfigSelection.Compile().Invoke(SETTINGS_MANAGER.ConfigurationData);
|
||||
var configInstance = this.ConfigSelection.Compile().Invoke(SettingsManagerAccess.ConfigurationData);
|
||||
var memberExpression = this.PropertyExpression.GetMemberExpression();
|
||||
if (memberExpression.Member is System.Reflection.PropertyInfo propertyInfo)
|
||||
propertyInfo.SetValue(configInstance, this.Default);
|
||||
@ -163,7 +163,7 @@ public record ConfigMeta<TClass, TValue> : ConfigMetaBase
|
||||
/// <param name="value">The value to set for the configuration property.</param>
|
||||
public void SetValue(TValue value)
|
||||
{
|
||||
var configInstance = this.ConfigSelection.Compile().Invoke(SETTINGS_MANAGER.ConfigurationData);
|
||||
var configInstance = this.ConfigSelection.Compile().Invoke(SettingsManagerAccess.ConfigurationData);
|
||||
var memberExpression = this.PropertyExpression.GetMemberExpression();
|
||||
if (memberExpression.Member is System.Reflection.PropertyInfo propertyInfo)
|
||||
propertyInfo.SetValue(configInstance, value);
|
||||
@ -174,7 +174,7 @@ public record ConfigMeta<TClass, TValue> : ConfigMetaBase
|
||||
/// </summary>
|
||||
public TValue GetValue()
|
||||
{
|
||||
var configInstance = this.ConfigSelection.Compile().Invoke(SETTINGS_MANAGER.ConfigurationData);
|
||||
var configInstance = this.ConfigSelection.Compile().Invoke(SettingsManagerAccess.ConfigurationData);
|
||||
var memberExpression = this.PropertyExpression.GetMemberExpression();
|
||||
if (memberExpression.Member is System.Reflection.PropertyInfo propertyInfo && propertyInfo.GetValue(configInstance) is TValue value)
|
||||
return value;
|
||||
|
||||
@ -2,5 +2,5 @@ namespace AIStudio.Settings;
|
||||
|
||||
public abstract record ConfigMetaBase : IConfig
|
||||
{
|
||||
protected static readonly SettingsManager SETTINGS_MANAGER = Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
protected static SettingsManager SettingsManagerAccess => Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
}
|
||||
@ -654,7 +654,7 @@ public static partial class ManagedConfiguration
|
||||
|
||||
if (successful)
|
||||
{
|
||||
var configInstance = configSelection.Compile().Invoke(SETTINGS_MANAGER.ConfigurationData);
|
||||
var configInstance = configSelection.Compile().Invoke(SettingsManagerAccess.ConfigurationData);
|
||||
var currentValue = propertyExpression.Compile().Invoke(configInstance);
|
||||
var merged = new HashSet<TValue>(currentValue);
|
||||
merged.UnionWith(configuredValue);
|
||||
|
||||
@ -9,7 +9,7 @@ namespace AIStudio.Settings;
|
||||
public static partial class ManagedConfiguration
|
||||
{
|
||||
private static readonly ConcurrentDictionary<string, IConfig> METADATA = new();
|
||||
private static readonly SettingsManager SETTINGS_MANAGER = Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
private static SettingsManager SettingsManagerAccess => Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to retrieve the configuration metadata for a given configuration selection and
|
||||
@ -418,19 +418,19 @@ public static partial class ManagedConfiguration
|
||||
|
||||
private static bool TryGetEditableDefaultState(string settingName, out ManagedEditableDefaultState editableDefaultState)
|
||||
{
|
||||
return SETTINGS_MANAGER.ConfigurationData.ManagedEditableDefaults.TryGetValue(settingName, out editableDefaultState!);
|
||||
return SettingsManagerAccess.ConfigurationData.ManagedEditableDefaults.TryGetValue(settingName, out editableDefaultState!);
|
||||
}
|
||||
|
||||
private static void SetEditableDefaultState(string settingName, Guid pluginId, string lastAppliedValue)
|
||||
{
|
||||
SETTINGS_MANAGER.ConfigurationData.ManagedEditableDefaults[settingName] = new()
|
||||
SettingsManagerAccess.ConfigurationData.ManagedEditableDefaults[settingName] = new()
|
||||
{
|
||||
ConfigPluginId = pluginId,
|
||||
LastAppliedValue = lastAppliedValue,
|
||||
};
|
||||
}
|
||||
|
||||
private static bool ClearEditableDefaultState(string settingName) => SETTINGS_MANAGER.ConfigurationData.ManagedEditableDefaults.Remove(settingName);
|
||||
private static bool ClearEditableDefaultState(string settingName) => SettingsManagerAccess.ConfigurationData.ManagedEditableDefaults.Remove(settingName);
|
||||
|
||||
private static bool CleanupEditableDefaultState<TClass, TValue>(
|
||||
ConfigMeta<TClass, TValue> configMeta,
|
||||
|
||||
@ -348,17 +348,13 @@ public sealed class SettingsManager
|
||||
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;
|
||||
}
|
||||
return this.GetProfileById(preselection.SpecificProfileId);
|
||||
|
||||
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;
|
||||
return this.GetProfileById(appPreselection.SpecificProfileId);
|
||||
}
|
||||
|
||||
public Profile GetAppPreselectedProfile()
|
||||
@ -367,8 +363,7 @@ public sealed class SettingsManager
|
||||
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;
|
||||
return this.GetProfileById(appPreselection.SpecificProfileId);
|
||||
}
|
||||
|
||||
public ChatTemplate GetPreselectedChatTemplate(Tools.Components component)
|
||||
@ -377,8 +372,29 @@ public sealed class SettingsManager
|
||||
if (preselection != ChatTemplate.NO_CHAT_TEMPLATE)
|
||||
return preselection;
|
||||
|
||||
preselection = this.ConfigurationData.ChatTemplates.FirstOrDefault(x => x.Id.Equals(this.ConfigurationData.App.PreselectedChatTemplate, StringComparison.OrdinalIgnoreCase));
|
||||
return preselection ?? ChatTemplate.NO_CHAT_TEMPLATE;
|
||||
return this.GetChatTemplateById(this.ConfigurationData.App.PreselectedChatTemplate);
|
||||
}
|
||||
|
||||
public Profile GetProfileById(string? profileId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(profileId))
|
||||
return Profile.NO_PROFILE;
|
||||
|
||||
if (string.Equals(profileId, Profile.NO_PROFILE.Id, StringComparison.OrdinalIgnoreCase))
|
||||
return Profile.NO_PROFILE;
|
||||
|
||||
return this.ConfigurationData.Profiles.FirstOrDefault(x => x.Id.Equals(profileId, StringComparison.OrdinalIgnoreCase)) ?? Profile.NO_PROFILE;
|
||||
}
|
||||
|
||||
public ChatTemplate GetChatTemplateById(string? chatTemplateId)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(chatTemplateId))
|
||||
return ChatTemplate.NO_CHAT_TEMPLATE;
|
||||
|
||||
if (string.Equals(chatTemplateId, ChatTemplate.NO_CHAT_TEMPLATE.Id, StringComparison.OrdinalIgnoreCase))
|
||||
return ChatTemplate.NO_CHAT_TEMPLATE;
|
||||
|
||||
return this.ConfigurationData.ChatTemplates.FirstOrDefault(x => x.Id.Equals(chatTemplateId, StringComparison.OrdinalIgnoreCase)) ?? ChatTemplate.NO_CHAT_TEMPLATE;
|
||||
}
|
||||
|
||||
public ConfidenceLevel GetConfiguredConfidenceLevel(LLMProviders llmProvider)
|
||||
|
||||
@ -169,7 +169,7 @@ public static class ComponentsExtensions
|
||||
|
||||
public static ChatTemplate PreselectedChatTemplate(this Components component, SettingsManager settingsManager) => component switch
|
||||
{
|
||||
Components.CHAT => settingsManager.ConfigurationData.Chat.PreselectOptions ? settingsManager.ConfigurationData.ChatTemplates.FirstOrDefault(x => x.Id == settingsManager.ConfigurationData.Chat.PreselectedChatTemplate) ?? ChatTemplate.NO_CHAT_TEMPLATE : ChatTemplate.NO_CHAT_TEMPLATE,
|
||||
Components.CHAT => settingsManager.ConfigurationData.Chat.PreselectOptions ? settingsManager.GetChatTemplateById(settingsManager.ConfigurationData.Chat.PreselectedChatTemplate) : ChatTemplate.NO_CHAT_TEMPLATE,
|
||||
|
||||
_ => ChatTemplate.NO_CHAT_TEMPLATE,
|
||||
};
|
||||
|
||||
@ -26,7 +26,7 @@ public static class ExternalHttpClientTimeout
|
||||
|
||||
private static string TB(string fallbackEN) => PluginSystem.I18N.I.T(fallbackEN, typeof(ExternalHttpClientTimeout).Namespace, nameof(ExternalHttpClientTimeout));
|
||||
private static readonly Lazy<ILogger> LOGGER = new(() => Program.LOGGER_FACTORY.CreateLogger(nameof(ExternalHttpClientTimeout)));
|
||||
private static readonly Lazy<SettingsManager> SETTINGS_MANAGER = new(() => Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>());
|
||||
private static SettingsManager SettingsManagerAccess => Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
private static readonly Lock CUSTOM_ROOT_CERTIFICATE_LOCK = new();
|
||||
private static CustomRootCertificateCache? CUSTOM_ROOT_CERTIFICATE_CACHE;
|
||||
|
||||
@ -91,7 +91,7 @@ public static class ExternalHttpClientTimeout
|
||||
|
||||
private static TimeSpan GetTimeout()
|
||||
{
|
||||
var seconds = SETTINGS_MANAGER.Value.ConfigurationData.App.HttpClientTimeoutSeconds;
|
||||
var seconds = SettingsManagerAccess.ConfigurationData.App.HttpClientTimeoutSeconds;
|
||||
if (seconds <= 0)
|
||||
seconds = DEFAULT_HTTP_CLIENT_TIMEOUT_SECONDS;
|
||||
|
||||
@ -129,11 +129,11 @@ public static class ExternalHttpClientTimeout
|
||||
|
||||
var enabled = TryParseBooleanEnvironmentValue(envEnabled, out var parsedEnvEnabled)
|
||||
? parsedEnvEnabled
|
||||
: SETTINGS_MANAGER.Value.ConfigurationData.App.ExternalHttpCustomRootCertificatesEnabled;
|
||||
: SettingsManagerAccess.ConfigurationData.App.ExternalHttpCustomRootCertificatesEnabled;
|
||||
|
||||
var bundlePath = !string.IsNullOrWhiteSpace(envBundlePath)
|
||||
? envBundlePath.Trim()
|
||||
: SETTINGS_MANAGER.Value.ConfigurationData.App.ExternalHttpCustomRootCertificateBundlePath.Trim();
|
||||
: SettingsManagerAccess.ConfigurationData.App.ExternalHttpCustomRootCertificateBundlePath.Trim();
|
||||
|
||||
var allowedHostPatterns = ReadAllowedHostPatterns(envAllowedHosts);
|
||||
var source = ReadCustomRootCertificateConfigurationSource(envEnabled, envBundlePath, envAllowedHosts);
|
||||
@ -158,7 +158,7 @@ public static class ExternalHttpClientTimeout
|
||||
{
|
||||
IEnumerable<string> rawPatterns = !string.IsNullOrWhiteSpace(envAllowedHosts)
|
||||
? envAllowedHosts.Split([';', ','], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
: SETTINGS_MANAGER.Value.ConfigurationData.App.ExternalHttpCustomRootCertificateAllowedHosts;
|
||||
: SettingsManagerAccess.ConfigurationData.App.ExternalHttpCustomRootCertificateAllowedHosts;
|
||||
|
||||
var patterns = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var rawPattern in rawPatterns)
|
||||
|
||||
@ -9,7 +9,7 @@ namespace AIStudio.Tools.PluginSystem;
|
||||
public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginType type) : PluginBase(isInternal, state, type)
|
||||
{
|
||||
private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(PluginConfiguration).Namespace, nameof(PluginConfiguration));
|
||||
private static readonly SettingsManager SETTINGS_MANAGER = Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
private static SettingsManager SettingsManagerAccess => Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger(nameof(PluginConfiguration));
|
||||
|
||||
private List<PluginConfigurationObject> configObjects = [];
|
||||
@ -41,7 +41,7 @@ public sealed class PluginConfiguration(bool isInternal, LuaState state, PluginT
|
||||
await StoreEnterpriseApiKeysAsync();
|
||||
await StoreEnterpriseSecretsAsync();
|
||||
|
||||
await SETTINGS_MANAGER.StoreSettings();
|
||||
await SettingsManagerAccess.StoreSettings();
|
||||
await MessageBus.INSTANCE.SendMessage<bool>(null, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,8 +14,9 @@ namespace AIStudio.Tools.PluginSystem;
|
||||
/// </summary>
|
||||
public sealed record PluginConfigurationObject
|
||||
{
|
||||
private static readonly RustService RUST_SERVICE = Program.SERVICE_PROVIDER.GetRequiredService<RustService>();
|
||||
private static readonly SettingsManager SETTINGS_MANAGER = Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
private static RustService RustService => Program.SERVICE_PROVIDER.GetRequiredService<RustService>();
|
||||
private static SettingsManager SettingsManagerAccess => Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
private static ThreadSafeRandom Rng => Program.SERVICE_PROVIDER.GetRequiredService<ThreadSafeRandom>();
|
||||
private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger<PluginConfigurationObject>();
|
||||
|
||||
/// <summary>
|
||||
@ -91,7 +92,8 @@ public sealed record PluginConfigurationObject
|
||||
return false;
|
||||
}
|
||||
|
||||
var storedObjects = configObjectSelection.Compile()(SETTINGS_MANAGER.ConfigurationData);
|
||||
var localSettingsManager = SettingsManagerAccess;
|
||||
var storedObjects = configObjectSelection.Compile()(localSettingsManager.ConfigurationData);
|
||||
var numberObjects = luaTable.ArrayLength;
|
||||
ThreadSafeRandom? random = null;
|
||||
for (var i = 1; i <= numberObjects; i++)
|
||||
@ -141,7 +143,7 @@ public sealed record PluginConfigurationObject
|
||||
// Case: The object does not exist, we have to add it
|
||||
else
|
||||
{
|
||||
if (nextConfigObjectNumSelection.TryIncrement(SETTINGS_MANAGER.ConfigurationData, IncrementType.POST) is { Success: true, UpdatedValue: var nextNum })
|
||||
if (nextConfigObjectNumSelection.TryIncrement(localSettingsManager.ConfigurationData, IncrementType.POST) is { Success: true, UpdatedValue: var nextNum })
|
||||
{
|
||||
// Case: Increment the next number was successful
|
||||
configObject = configObject with { Num = nextNum };
|
||||
@ -150,7 +152,7 @@ public sealed record PluginConfigurationObject
|
||||
else
|
||||
{
|
||||
// Case: The next number could not be incremented, we use a random number
|
||||
random ??= new ThreadSafeRandom();
|
||||
random ??= Rng;
|
||||
configObject = configObject with { Num = (uint)random.Next(500_000, 1_000_000) };
|
||||
storedObjects.Add((TClass)configObject);
|
||||
LOG.LogWarning("The next number for the configuration object '{ConfigObjectName}' (id={ConfigObjectId}) could not be incremented. Using a random number instead (config plugin id: {ConfigPluginId}).", configObject.Name, configObject.Id, configPluginId);
|
||||
@ -185,7 +187,8 @@ public sealed record PluginConfigurationObject
|
||||
return false;
|
||||
}
|
||||
|
||||
var storedObjects = SETTINGS_MANAGER.ConfigurationData.DataSources;
|
||||
var localSettingsManager = SettingsManagerAccess;
|
||||
var storedObjects = localSettingsManager.ConfigurationData.DataSources;
|
||||
var numberObjects = luaTable.ArrayLength;
|
||||
ThreadSafeRandom? random = null;
|
||||
for (var i = 1; i <= numberObjects; i++)
|
||||
@ -222,14 +225,14 @@ public sealed record PluginConfigurationObject
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IncrementDataSourceNum() is { Success: true, UpdatedValue: var nextNum })
|
||||
if (IncrementDataSourceNum(localSettingsManager.ConfigurationData) is { Success: true, UpdatedValue: var nextNum })
|
||||
{
|
||||
configObject = configObject with { Num = nextNum };
|
||||
storedObjects.Add(configObject);
|
||||
}
|
||||
else
|
||||
{
|
||||
random ??= new ThreadSafeRandom();
|
||||
random ??= Rng;
|
||||
configObject = configObject with { Num = (uint)random.Next(500_000, 1_000_000) };
|
||||
storedObjects.Add(configObject);
|
||||
LOG.LogWarning("The next number for the data source '{ConfigObjectName}' (id={ConfigObjectId}) could not be incremented. Using a random number instead (config plugin id: {ConfigPluginId}).", configObject.Name, configObject.Id, configPluginId);
|
||||
@ -239,9 +242,9 @@ public sealed record PluginConfigurationObject
|
||||
|
||||
return true;
|
||||
|
||||
static IncrementResult<uint> IncrementDataSourceNum()
|
||||
static IncrementResult<uint> IncrementDataSourceNum(Data data)
|
||||
{
|
||||
return ((Expression<Func<Data, uint>>)(x => x.NextDataSourceNum)).TryIncrement(SETTINGS_MANAGER.ConfigurationData, IncrementType.POST);
|
||||
return ((Expression<Func<Data, uint>>)(x => x.NextDataSourceNum)).TryIncrement(data, IncrementType.POST);
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,7 +267,8 @@ public sealed record PluginConfigurationObject
|
||||
SecretStoreType? secretStoreType = null,
|
||||
bool deleteSecret = false) where TClass : IConfigurationObject
|
||||
{
|
||||
var configuredObjects = configObjectSelection.Compile()(SETTINGS_MANAGER.ConfigurationData);
|
||||
var localSettingsManager = SettingsManagerAccess;
|
||||
var configuredObjects = configObjectSelection.Compile()(localSettingsManager.ConfigurationData);
|
||||
var leftOverObjects = new List<TClass>();
|
||||
foreach (var configuredObject in configuredObjects)
|
||||
{
|
||||
@ -307,7 +311,7 @@ public sealed record PluginConfigurationObject
|
||||
// Delete the API key from the OS keyring if the removed object has one:
|
||||
if(deleteSecret && item is ISecretId regularSecretId)
|
||||
{
|
||||
var deleteResult = await RUST_SERVICE.DeleteSecret(regularSecretId, secretStoreType ?? SecretStoreType.DATA_SOURCE);
|
||||
var deleteResult = await RustService.DeleteSecret(regularSecretId, secretStoreType ?? SecretStoreType.DATA_SOURCE);
|
||||
if (deleteResult.Success)
|
||||
LOG.LogInformation($"Successfully deleted secret for removed enterprise object '{item.Name}' from the OS keyring.");
|
||||
else
|
||||
@ -315,7 +319,7 @@ public sealed record PluginConfigurationObject
|
||||
}
|
||||
else if(secretStoreType is not null && item is ISecretId secretId)
|
||||
{
|
||||
var deleteResult = await RUST_SERVICE.DeleteAPIKey(secretId, secretStoreType.Value);
|
||||
var deleteResult = await RustService.DeleteAPIKey(secretId, secretStoreType.Value);
|
||||
if (deleteResult.Success)
|
||||
LOG.LogInformation($"Successfully deleted API key for removed enterprise provider '{item.Name}' from the OS keyring.");
|
||||
else
|
||||
|
||||
@ -191,7 +191,7 @@ public static partial class PluginFactory
|
||||
wasConfigurationChanged = true;
|
||||
|
||||
// Check left-over mandatory info acceptances:
|
||||
if (SETTINGS_MANAGER.ConfigurationData.MandatoryInformation.RemoveLeftOverAcceptances(GetMandatoryInfos()))
|
||||
if (SettingsManagerAccess.ConfigurationData.MandatoryInformation.RemoveLeftOverAcceptances(GetMandatoryInfos()))
|
||||
wasConfigurationChanged = true;
|
||||
|
||||
// Check for a preselected provider:
|
||||
@ -285,7 +285,7 @@ public static partial class PluginFactory
|
||||
|
||||
if (wasConfigurationChanged)
|
||||
{
|
||||
await SETTINGS_MANAGER.StoreSettings();
|
||||
await SettingsManagerAccess.StoreSettings();
|
||||
await MessageBus.INSTANCE.SendMessage<bool>(null, Event.CONFIGURATION_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +64,7 @@ public static partial class PluginFactory
|
||||
|
||||
try
|
||||
{
|
||||
if (availablePlugin.IsInternal || SETTINGS_MANAGER.IsPluginEnabled(availablePlugin) || availablePlugin.Type == PluginType.CONFIGURATION || availablePlugin.Type == PluginType.ASSISTANT)
|
||||
if (availablePlugin.IsInternal || SettingsManagerAccess.IsPluginEnabled(availablePlugin) || availablePlugin.Type == PluginType.CONFIGURATION || availablePlugin.Type == PluginType.ASSISTANT)
|
||||
if(await Start(availablePlugin, cancellationToken) is { IsValid: true } plugin)
|
||||
{
|
||||
if (plugin is PluginConfiguration configPlugin)
|
||||
|
||||
@ -6,7 +6,7 @@ namespace AIStudio.Tools.PluginSystem;
|
||||
public static partial class PluginFactory
|
||||
{
|
||||
private static readonly ILogger LOG = Program.LOGGER_FACTORY.CreateLogger(nameof(PluginFactory));
|
||||
private static readonly SettingsManager SETTINGS_MANAGER = Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
private static SettingsManager SettingsManagerAccess => Program.SERVICE_PROVIDER.GetRequiredService<SettingsManager>();
|
||||
|
||||
private static string DATA_DIR = string.Empty;
|
||||
private static string PLUGINS_ROOT = string.Empty;
|
||||
|
||||
@ -6,7 +6,7 @@ namespace AIStudio.Tools.RAG;
|
||||
|
||||
public static class IRetrievalContextExtensions
|
||||
{
|
||||
private static readonly ILogger<IRetrievalContext> LOGGER = Program.SERVICE_PROVIDER.GetService<ILogger<IRetrievalContext>>()!;
|
||||
private static readonly ILogger<IRetrievalContext> LOGGER = Program.LOGGER_FACTORY.CreateLogger<IRetrievalContext>();
|
||||
|
||||
public static async Task<string> AsMarkdown(this IReadOnlyList<IRetrievalContext> retrievalContexts, StringBuilder? sb = null, CancellationToken token = default)
|
||||
{
|
||||
|
||||
@ -17,7 +17,6 @@ public sealed class TemporaryChatService(ILogger<TemporaryChatService> logger, S
|
||||
|
||||
logger.LogInformation("The temporary chat maintenance service was initialized.");
|
||||
|
||||
await settingsManager.LoadSettings();
|
||||
if(settingsManager.ConfigurationData.Workspace.StorageTemporaryMaintenancePolicy is WorkspaceStorageTemporaryMaintenancePolicy.NO_AUTOMATIC_MAINTENANCE)
|
||||
{
|
||||
logger.LogWarning("Automatic maintenance of temporary chat storage is disabled. Exiting maintenance service.");
|
||||
|
||||
@ -10,6 +10,8 @@
|
||||
- Improved workspaces by allowing new workspaces to be created while moving a chat.
|
||||
- Improved voice recording shortcut labels so they match the user's keyboard layout after being configured.
|
||||
- Improved the enterprise configuration details on the information page by showing where each configuration comes from and which configuration slot was used.
|
||||
- Fixed an issue where newly added profiles and chat templates were not usable until the app was restarted.
|
||||
- Fixed an issue where renamed chat templates and profiles continued to show their old names in the chat toolbar until the app was restarted.
|
||||
- Fixed workspace creation and renaming to prevent new workspaces from using an existing name.
|
||||
- Fixed an issue on Microsoft Windows where reading attached documents could briefly open a terminal window while processing files.
|
||||
- Upgraded dependencies.
|
||||
@ -11,4 +11,5 @@
|
||||
MWAIS0005 | Usage | Error | ThisUsageAnalyzer
|
||||
MWAIS0006 | Style | Error | SwitchExpressionMethodAnalyzer
|
||||
MWAIS0007 | Usage | Error | EmptyStringAnalyzer
|
||||
MWAIS0008 | Naming | Error | LocalConstantsAnalyzer
|
||||
MWAIS0008 | Naming | Error | LocalConstantsAnalyzer
|
||||
MWAIS0009 | Usage | Error | StaticServiceProviderCacheAnalyzer
|
||||
@ -10,4 +10,5 @@ public static class Identifier
|
||||
public const string SWITCH_EXPRESSION_METHOD_ANALYZER = $"{Tools.ID_PREFIX}0006";
|
||||
public const string EMPTY_STRING_ANALYZER = $"{Tools.ID_PREFIX}0007";
|
||||
public const string LOCAL_CONSTANTS_ANALYZER = $"{Tools.ID_PREFIX}0008";
|
||||
public const string STATIC_SERVICE_PROVIDER_CACHE_ANALYZER = $"{Tools.ID_PREFIX}0009";
|
||||
}
|
||||
@ -0,0 +1,159 @@
|
||||
using System.Collections.Immutable;
|
||||
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Diagnostics;
|
||||
|
||||
namespace SourceCodeRules.UsageAnalyzers;
|
||||
|
||||
#pragma warning disable RS1038
|
||||
[DiagnosticAnalyzer(LanguageNames.CSharp)]
|
||||
#pragma warning restore RS1038
|
||||
public sealed class StaticServiceProviderCacheAnalyzer : DiagnosticAnalyzer
|
||||
{
|
||||
private const string DIAGNOSTIC_ID = Identifier.STATIC_SERVICE_PROVIDER_CACHE_ANALYZER;
|
||||
|
||||
private static readonly string TITLE = "Services from Program.SERVICE_PROVIDER must not be cached in static state";
|
||||
|
||||
private static readonly string MESSAGE_FORMAT = "Do not cache services from Program.SERVICE_PROVIDER in static state. Use constructor injection, method-local resolution, or a non-caching get-only property.";
|
||||
|
||||
private static readonly string DESCRIPTION = MESSAGE_FORMAT;
|
||||
|
||||
private const string CATEGORY = "Usage";
|
||||
|
||||
private static readonly DiagnosticDescriptor RULE = new(DIAGNOSTIC_ID, TITLE, MESSAGE_FORMAT, CATEGORY, DiagnosticSeverity.Error, isEnabledByDefault: true, description: DESCRIPTION);
|
||||
|
||||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [RULE];
|
||||
|
||||
public override void Initialize(AnalysisContext context)
|
||||
{
|
||||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
|
||||
context.EnableConcurrentExecution();
|
||||
context.RegisterSyntaxNodeAction(this.AnalyzeFieldDeclaration, SyntaxKind.FieldDeclaration);
|
||||
context.RegisterSyntaxNodeAction(this.AnalyzeVariableDeclarator, SyntaxKind.VariableDeclarator);
|
||||
context.RegisterSyntaxNodeAction(this.AnalyzePropertyDeclaration, SyntaxKind.PropertyDeclaration);
|
||||
context.RegisterSyntaxNodeAction(this.AnalyzeAssignmentExpression, SyntaxKind.SimpleAssignmentExpression);
|
||||
}
|
||||
|
||||
private void AnalyzeFieldDeclaration(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
var fieldDeclaration = (FieldDeclarationSyntax)context.Node;
|
||||
foreach (var variable in fieldDeclaration.Declaration.Variables)
|
||||
this.AnalyzeStaticFieldInitializer(context, variable);
|
||||
}
|
||||
|
||||
private void AnalyzeVariableDeclarator(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
var variable = (VariableDeclaratorSyntax)context.Node;
|
||||
if (variable.Parent?.Parent is FieldDeclarationSyntax)
|
||||
return;
|
||||
|
||||
this.AnalyzeStaticFieldInitializer(context, variable);
|
||||
}
|
||||
|
||||
private void AnalyzePropertyDeclaration(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
var propertyDeclaration = (PropertyDeclarationSyntax)context.Node;
|
||||
if (propertyDeclaration.Initializer is null)
|
||||
return;
|
||||
|
||||
if (context.SemanticModel.GetDeclaredSymbol(propertyDeclaration) is not { IsStatic: true })
|
||||
return;
|
||||
|
||||
if (!this.IsProgramServiceProviderGetCall(propertyDeclaration.Initializer.Value))
|
||||
return;
|
||||
|
||||
var diagnostic = Diagnostic.Create(RULE, propertyDeclaration.Initializer.Value.GetLocation());
|
||||
context.ReportDiagnostic(diagnostic);
|
||||
}
|
||||
|
||||
private void AnalyzeAssignmentExpression(SyntaxNodeAnalysisContext context)
|
||||
{
|
||||
var assignment = (AssignmentExpressionSyntax)context.Node;
|
||||
if (!this.IsProgramServiceProviderGetCall(assignment.Right))
|
||||
return;
|
||||
|
||||
var targetSymbol = context.SemanticModel.GetSymbolInfo(assignment.Left).Symbol;
|
||||
if (targetSymbol is not IFieldSymbol { IsStatic: true } && targetSymbol is not IPropertySymbol { IsStatic: true })
|
||||
return;
|
||||
|
||||
var diagnostic = Diagnostic.Create(RULE, assignment.Right.GetLocation());
|
||||
context.ReportDiagnostic(diagnostic);
|
||||
}
|
||||
|
||||
private void AnalyzeStaticFieldInitializer(SyntaxNodeAnalysisContext context, VariableDeclaratorSyntax variable)
|
||||
{
|
||||
if (variable.Initializer is null)
|
||||
return;
|
||||
|
||||
if (context.SemanticModel.GetDeclaredSymbol(variable) is not IFieldSymbol { IsStatic: true })
|
||||
return;
|
||||
|
||||
if (!this.IsProgramServiceProviderGetCall(variable.Initializer.Value))
|
||||
return;
|
||||
|
||||
var diagnostic = Diagnostic.Create(RULE, variable.Initializer.Value.GetLocation());
|
||||
context.ReportDiagnostic(diagnostic);
|
||||
}
|
||||
|
||||
private bool IsProgramServiceProviderGetCall(ExpressionSyntax expression)
|
||||
{
|
||||
if (this.UnwrapSimpleExpression(expression) is not InvocationExpressionSyntax invocation)
|
||||
return false;
|
||||
|
||||
if (this.UnwrapSimpleExpression(invocation.Expression) is not MemberAccessExpressionSyntax memberAccess)
|
||||
return false;
|
||||
|
||||
if (!this.IsServiceProviderGetMethod(memberAccess.Name))
|
||||
return false;
|
||||
|
||||
return this.IsProgramServiceProviderAccess(memberAccess.Expression);
|
||||
}
|
||||
|
||||
private bool IsServiceProviderGetMethod(SimpleNameSyntax name) => name switch
|
||||
{
|
||||
GenericNameSyntax genericName when genericName.TypeArgumentList.Arguments.Count == 1 =>
|
||||
genericName.Identifier.Text is "GetService" or "GetRequiredService",
|
||||
_ => false,
|
||||
};
|
||||
|
||||
private bool IsProgramServiceProviderAccess(ExpressionSyntax expression)
|
||||
{
|
||||
if (this.UnwrapSimpleExpression(expression) is not MemberAccessExpressionSyntax memberAccess)
|
||||
return false;
|
||||
|
||||
if (memberAccess.Name.Identifier.Text != "SERVICE_PROVIDER")
|
||||
return false;
|
||||
|
||||
return this.UnwrapSimpleExpression(memberAccess.Expression) is IdentifierNameSyntax { Identifier.Text: "Program" };
|
||||
}
|
||||
|
||||
private ExpressionSyntax UnwrapSimpleExpression(ExpressionSyntax expression)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
switch (expression)
|
||||
{
|
||||
case ParenthesizedExpressionSyntax parenthesized:
|
||||
expression = parenthesized.Expression;
|
||||
continue;
|
||||
|
||||
case PostfixUnaryExpressionSyntax { RawKind: (int)SyntaxKind.SuppressNullableWarningExpression } postfixUnary:
|
||||
expression = postfixUnary.Operand;
|
||||
continue;
|
||||
|
||||
case CastExpressionSyntax castExpression:
|
||||
expression = castExpression.Expression;
|
||||
continue;
|
||||
|
||||
case BinaryExpressionSyntax { RawKind: (int)SyntaxKind.AsExpression } asExpression:
|
||||
expression = asExpression.Left;
|
||||
continue;
|
||||
|
||||
default:
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user