mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-11-13 10:47:21 +00:00
Changed all icons of AI Studio to Lucide (#1187)
This commit is contained in:
1 parent
9a676101f7
commit
7ef26cd5c8
352 files changed
+6261
-1620
No files matched your search
@@ -301,7 +301,7 @@ public sealed class AIJobService(SettingsManager settingsManager, MessageBus mes
|
||||
// The answer is about to be created without the data the user expected it to use.
|
||||
// Without this message, that answer is indistinguishable from one that did use it:
|
||||
//
|
||||
await MessageBus.INSTANCE.SendWarning(new(Icons.Material.Filled.Source, TB("Your data sources could not be used. This answer was created without them.")));
|
||||
await MessageBus.INSTANCE.SendWarning(new(AppIcons.DATA_SOURCE, TB("Your data sources could not be used. This answer was created without them.")));
|
||||
}
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
@@ -344,13 +344,13 @@ public sealed class AIJobService(SettingsManager settingsManager, MessageBus mes
|
||||
logger.LogError(e, "The provider request failed for chat generation job '{JobId}'. Status={StatusCode}, Reason='{ReasonPhrase}', Body='{ResponseBody}'", state.Snapshot.JobId, e.StatusCode, e.ReasonPhrase, e.ResponseBody);
|
||||
RemoveEmptyAIResponse(state);
|
||||
await this.CompleteChatGenerationAsync(state, AIJobStatus.FAILED, e.UserMessage);
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.CloudOff, e.UserMessage));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.PROVIDER_ERROR, e.UserMessage));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.LogError(e, "The chat generation job '{JobId}' failed.", state.Snapshot.JobId);
|
||||
await this.CompleteChatGenerationAsync(state, AIJobStatus.FAILED, e.Message);
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Stream, string.Format(TB("The AI job failed. The message is: '{0}'"), e.Message)));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.ANSWER_STREAM, string.Format(TB("The AI job failed. The message is: '{0}'"), e.Message)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,7 +567,7 @@ public sealed class AIJobService(SettingsManager settingsManager, MessageBus mes
|
||||
{
|
||||
var userMessage = modelLoadResult.FailureReason.ToUserMessage(provider.InstanceName);
|
||||
if (!string.IsNullOrWhiteSpace(userMessage))
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.CloudOff, userMessage));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.PROVIDER_ERROR, userMessage));
|
||||
|
||||
logger.LogWarning("Skipping selected model availability check for '{ProviderInstanceName}' (provider={ProviderType}) because loading the model list failed with reason {FailureReason}.", provider.InstanceName, provider.Provider, modelLoadResult.FailureReason);
|
||||
return false;
|
||||
@@ -592,7 +592,7 @@ public sealed class AIJobService(SettingsManager settingsManager, MessageBus mes
|
||||
TB("We could load models from '{0}', but the provider did not return any usable text models."),
|
||||
provider.InstanceName);
|
||||
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.CloudOff, emptyModelsMessage));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.PROVIDER_ERROR, emptyModelsMessage));
|
||||
logger.LogWarning("Skipping AI request because there are no models available from '{ProviderInstanceName}' (provider={ProviderType}).", provider.InstanceName, provider.Provider);
|
||||
return false;
|
||||
}
|
||||
@@ -606,7 +606,7 @@ public sealed class AIJobService(SettingsManager settingsManager, MessageBus mes
|
||||
provider.InstanceName,
|
||||
provider.Provider);
|
||||
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.CloudOff, message));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.PROVIDER_ERROR, message));
|
||||
logger.LogWarning("Skipping AI request because model '{ModelId}' is not available from '{ProviderInstanceName}' (provider={ProviderType}).", chatModel.Id, provider.InstanceName, provider.Provider);
|
||||
return false;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -93,7 +93,7 @@ public sealed class AssistantLaunchService(SettingsManager settingsManager, Assi
|
||||
var route = destination.GetData().Route;
|
||||
if (destination.HasSingleSessionSlot && assistantSessionService.GetSnapshots().Any(snapshot => snapshot.IsActive && snapshot.Key.Component == destination))
|
||||
{
|
||||
await MessageBus.INSTANCE.SendWarning(new(Icons.Material.Filled.Apps, TB("This assistant is already running. AI Studio opens the running session instead.")));
|
||||
await MessageBus.INSTANCE.SendWarning(new(AppIcons.ASSISTANTS, TB("This assistant is already running. AI Studio opens the running session instead.")));
|
||||
navigationManager.NavigateTo(route);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -85,15 +85,15 @@ public static class FileExportFormatExtensions
|
||||
/// <value>The icon of the format.</value>
|
||||
public string Icon => format switch
|
||||
{
|
||||
FileExportFormat.MICROSOFT_WORD => Icons.Custom.FileFormats.FileWord,
|
||||
FileExportFormat.OPEN_DOCUMENT_TEXT => Icons.Custom.FileFormats.FileDocument,
|
||||
FileExportFormat.LATEX => Icons.Material.Filled.Functions,
|
||||
FileExportFormat.MARKDOWN => Icons.Material.Filled.TextFields,
|
||||
FileExportFormat.HTML => Icons.Material.Filled.Html,
|
||||
FileExportFormat.CSV or FileExportFormat.TSV => Icons.Material.Filled.TableChart,
|
||||
FileExportFormat.SOURCE_CODE => Icons.Material.Filled.Code,
|
||||
FileExportFormat.MICROSOFT_WORD => AppIcons.FILE_FORMAT_WORD,
|
||||
FileExportFormat.OPEN_DOCUMENT_TEXT => AppIcons.FILE_FORMAT_ODT,
|
||||
FileExportFormat.LATEX => AppIcons.FILE_FORMAT_LATEX,
|
||||
FileExportFormat.MARKDOWN => AppIcons.FILE_FORMAT_MARKDOWN,
|
||||
FileExportFormat.HTML => AppIcons.FILE_FORMAT_HTML,
|
||||
FileExportFormat.CSV or FileExportFormat.TSV => AppIcons.FILE_FORMAT_TABLE,
|
||||
FileExportFormat.SOURCE_CODE => AppIcons.CODE,
|
||||
|
||||
_ => Icons.Material.Filled.Help,
|
||||
_ => AppIcons.UNKNOWN,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -71,7 +71,7 @@ public static partial class Pandoc
|
||||
if (process == null)
|
||||
{
|
||||
if (showMessages)
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Help, TB("Was not able to check the Pandoc installation.")));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.UNKNOWN, TB("Was not able to check the Pandoc installation.")));
|
||||
|
||||
LOG.LogError("The Pandoc process was not started, it was null. Executable path: '{Executable}'.", preparedProcess.StartInfo.FileName);
|
||||
|
||||
@@ -90,7 +90,7 @@ public static partial class Pandoc
|
||||
if (process.ExitCode != 0)
|
||||
{
|
||||
if (showMessages)
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Error, TB("Pandoc is not available on the system or the process had issues.")));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.PANDOC_UNAVAILABLE, TB("Pandoc is not available on the system or the process had issues.")));
|
||||
|
||||
LOG.LogError("The Pandoc process exited with code {ProcessExitCode}. Error output: '{ErrorText}'", process.ExitCode, error);
|
||||
|
||||
@@ -101,7 +101,7 @@ public static partial class Pandoc
|
||||
if (!versionMatch.Success)
|
||||
{
|
||||
if (showMessages)
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Terminal, TB("Was not able to validate the Pandoc installation.")));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.PANDOC, TB("Was not able to validate the Pandoc installation.")));
|
||||
|
||||
LOG.LogError("Pandoc --version returned an invalid format: '{Output}'.", output);
|
||||
|
||||
@@ -115,7 +115,7 @@ public static partial class Pandoc
|
||||
if (installedVersion >= MINIMUM_REQUIRED_VERSION)
|
||||
{
|
||||
if (showMessages && showSuccessMessage)
|
||||
await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, string.Format(TB("Pandoc v{0} is installed."), installedVersionString)));
|
||||
await MessageBus.INSTANCE.SendSuccess(new(AppIcons.SUCCESS, string.Format(TB("Pandoc v{0} is installed."), installedVersionString)));
|
||||
|
||||
if (!HAS_LOGGED_SUCCESSFUL_CHECK_ONCE)
|
||||
{
|
||||
@@ -127,7 +127,7 @@ public static partial class Pandoc
|
||||
}
|
||||
|
||||
if (showMessages)
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Build, string.Format(TB("Pandoc v{0} is installed, but it doesn't match the required version (v{1})."), installedVersionString, MINIMUM_REQUIRED_VERSION.ToString())));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.PANDOC_UNAVAILABLE, string.Format(TB("Pandoc v{0} is installed, but it doesn't match the required version (v{1})."), installedVersionString, MINIMUM_REQUIRED_VERSION.ToString())));
|
||||
|
||||
LOG.LogWarning("Pandoc v{0} is installed, but it does not match the required version (v{1}).", installedVersionString, MINIMUM_REQUIRED_VERSION.ToString());
|
||||
|
||||
@@ -136,7 +136,7 @@ public static partial class Pandoc
|
||||
catch (Exception e)
|
||||
{
|
||||
if (showMessages)
|
||||
await MessageBus.INSTANCE.SendError(new(@Icons.Material.Filled.AppsOutage, TB("Pandoc doesn't seem to be installed.")));
|
||||
await MessageBus.INSTANCE.SendError(new(@AppIcons.PANDOC_UNAVAILABLE, TB("Pandoc doesn't seem to be installed.")));
|
||||
|
||||
LOG.LogError(e, "Pandoc availability check failed. This usually means Pandoc is not installed or not in the system PATH.");
|
||||
|
||||
@@ -172,7 +172,7 @@ public static partial class Pandoc
|
||||
var uri = GenerateArchiveUri(latestVersion);
|
||||
if (string.IsNullOrWhiteSpace(uri))
|
||||
{
|
||||
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Error, TB("AI Studio couldn't install Pandoc because the archive type is unknown.")));
|
||||
await MessageBus.INSTANCE.SendError(new (AppIcons.ERROR, TB("AI Studio couldn't install Pandoc because the archive type is unknown.")));
|
||||
LOG.LogError("Pandoc was not installed, no archive is available for architecture '{Architecture}'.", CPU_ARCHITECTURE.UserFriendlyName);
|
||||
return;
|
||||
}
|
||||
@@ -180,7 +180,7 @@ public static partial class Pandoc
|
||||
using var response = await WEB_CLIENT.GetAsync(uri);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Error, TB("AI Studio couldn't install Pandoc because the archive was not found.")));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.ERROR, TB("AI Studio couldn't install Pandoc because the archive was not found.")));
|
||||
LOG.LogError("Pandoc was not installed successfully, because the archive was not found (status code {0}): url='{1}', message='{2}'", response.StatusCode, uri, response.RequestMessage);
|
||||
return;
|
||||
}
|
||||
@@ -212,7 +212,7 @@ public static partial class Pandoc
|
||||
}
|
||||
else
|
||||
{
|
||||
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Error, TB("AI Studio couldn't install Pandoc because the archive type is unknown.")));
|
||||
await MessageBus.INSTANCE.SendError(new (AppIcons.ERROR, TB("AI Studio couldn't install Pandoc because the archive type is unknown.")));
|
||||
LOG.LogError("Pandoc was not installed, the archive is unknown: url='{0}'", uri);
|
||||
return;
|
||||
}
|
||||
@@ -220,7 +220,7 @@ public static partial class Pandoc
|
||||
var stagedPandocExecutable = FindExecutableInDirectory(stagingDir, PandocProcessBuilder.PandocExecutableName);
|
||||
if (string.IsNullOrWhiteSpace(stagedPandocExecutable))
|
||||
{
|
||||
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Error, TB("AI Studio couldn't install Pandoc because the executable was not found in the archive.")));
|
||||
await MessageBus.INSTANCE.SendError(new (AppIcons.ERROR, TB("AI Studio couldn't install Pandoc because the executable was not found in the archive.")));
|
||||
LOG.LogError("Pandoc was not installed, the executable was not found in the extracted archive: '{StagingDir}'.", stagingDir);
|
||||
return;
|
||||
}
|
||||
@@ -228,12 +228,12 @@ public static partial class Pandoc
|
||||
LOG.LogInformation("Found Pandoc executable in downloaded archive: '{Executable}'.", stagedPandocExecutable);
|
||||
|
||||
await ReplaceInstallationDirectoryAsync(stagingDir, installDir);
|
||||
await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.CheckCircle, string.Format(TB("Pandoc v{0} was installed successfully."), latestVersion)));
|
||||
await MessageBus.INSTANCE.SendSuccess(new(AppIcons.SUCCESS, string.Format(TB("Pandoc v{0} was installed successfully."), latestVersion)));
|
||||
LOG.LogInformation("Pandoc v{0} was installed successfully.", latestVersion);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Error, TB("AI Studio couldn't install Pandoc.")));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.ERROR, TB("AI Studio couldn't install Pandoc.")));
|
||||
LOG.LogError(ex, "An error occurred while installing Pandoc.");
|
||||
}
|
||||
finally
|
||||
@@ -384,7 +384,7 @@ public static partial class Pandoc
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
LOG.LogError("Code {StatusCode}: Could not fetch Pandoc's latest page: {Response}", response.StatusCode, response.RequestMessage);
|
||||
await MessageBus.INSTANCE.SendWarning(new (Icons.Material.Filled.Warning, string.Format(TB("AI Studio couldn't find the latest Pandoc version and will install version {0} instead."), FALLBACK_VERSION.ToString())));
|
||||
await MessageBus.INSTANCE.SendWarning(new (AppIcons.WARNING, string.Format(TB("AI Studio couldn't find the latest Pandoc version and will install version {0} instead."), FALLBACK_VERSION.ToString())));
|
||||
return FALLBACK_VERSION.ToString();
|
||||
}
|
||||
|
||||
@@ -393,7 +393,7 @@ public static partial class Pandoc
|
||||
if (!versionMatch.Success)
|
||||
{
|
||||
LOG.LogError("The latest version regex returned nothing: {0}", versionMatch.Groups.ToString());
|
||||
await MessageBus.INSTANCE.SendWarning(new (Icons.Material.Filled.Warning, string.Format(TB("AI Studio couldn't find the latest Pandoc version and will install version {0} instead."), FALLBACK_VERSION.ToString())));
|
||||
await MessageBus.INSTANCE.SendWarning(new (AppIcons.WARNING, string.Format(TB("AI Studio couldn't find the latest Pandoc version and will install version {0} instead."), FALLBACK_VERSION.ToString())));
|
||||
return FALLBACK_VERSION.ToString();
|
||||
}
|
||||
|
||||
@@ -473,7 +473,7 @@ public static partial class Pandoc
|
||||
return $"{baseUri}arm64-macOS.pkg";
|
||||
|
||||
default:
|
||||
await MessageBus.INSTANCE.SendError(new (Icons.Material.Filled.Terminal, string.Format(TB("Installers are not available on {0} systems."), CPU_ARCHITECTURE.UserFriendlyName)));
|
||||
await MessageBus.INSTANCE.SendError(new (AppIcons.PANDOC, string.Format(TB("Installers are not available on {0} systems."), CPU_ARCHITECTURE.UserFriendlyName)));
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ public static class PandocExport
|
||||
if (!markdownContent.TryGetExportMarkdown(out var markdownText, format.FollowsPageAnchors))
|
||||
{
|
||||
LOGGER.LogWarning("Cannot export the content as {ExportFormat}, because it carries no text.", format);
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Cancel, TB("Only text messages can be exported.")));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.WARNING, TB("Only text messages can be exported.")));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -165,11 +165,11 @@ public static class PandocExport
|
||||
feedback.ShowRunning(response.SaveFilePath);
|
||||
if (!await ConvertAsync(rustService, markdownText, response.SaveFilePath, format))
|
||||
{
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Cancel, TB("The export failed.")));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.ERROR, TB("The export failed.")));
|
||||
return false;
|
||||
}
|
||||
|
||||
await feedback.SucceededAsync(Icons.Material.Filled.CheckCircle, TB("The export succeeded."), response.SaveFilePath, true);
|
||||
await feedback.SucceededAsync(AppIcons.SUCCESS, TB("The export succeeded."), response.SaveFilePath, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -284,14 +284,14 @@ public static class PlainFileExport
|
||||
try
|
||||
{
|
||||
await File.WriteAllTextAsync(response.SaveFilePath, fileContent, encoding);
|
||||
await feedback.SucceededAsync(Icons.Material.Filled.CheckCircle, TB("The export succeeded."), response.SaveFilePath, true);
|
||||
await feedback.SucceededAsync(AppIcons.SUCCESS, TB("The export succeeded."), response.SaveFilePath, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOGGER.LogError(ex, "Error during {ExportFormat} export.", format);
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Cancel, TB("The export failed.")));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.ERROR, TB("The export failed.")));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+21
-1
@@ -4,6 +4,11 @@ namespace AIStudio.Tools.PluginSystem.Assistants.DataModel;
|
||||
|
||||
internal static class AssistantComponentPropHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// The prefix with which an assistant plugin names a Lucide icon.
|
||||
/// </summary>
|
||||
private const string LUCIDE_PREFIX = "lucide:";
|
||||
|
||||
public static string ReadString(Dictionary<string, object> props, string key)
|
||||
{
|
||||
if (props.TryGetValue(key, out var value))
|
||||
@@ -52,7 +57,22 @@ internal static class AssistantComponentPropHelper
|
||||
public static Color GetColor(string value, Color fallback) => Enum.TryParse<Color>(value, out var color) ? color : fallback;
|
||||
public static Variant GetVariant(string value, Variant fallback) => Enum.TryParse<Variant>(value, out var variant) ? variant : fallback;
|
||||
public static Adornment GetAdornment(string value, Adornment fallback) => Enum.TryParse<Adornment>(value, out var adornment) ? adornment : fallback;
|
||||
public static string GetIconSvg(string value) => MudBlazorIconRegistry.TryGetSvg(value.TrimStart('@'), out var svg) ? svg : string.Empty;
|
||||
/// <summary>
|
||||
/// Finds the icon an assistant plugin names: a Lucide icon as "lucide:" followed by its name on lucide.dev,
|
||||
/// such as "lucide:house", or an icon of MudBlazor, such as "Icons.Material.Filled.Home".
|
||||
/// </summary>
|
||||
/// <param name="value">The icon as the plugin names it.</param>
|
||||
/// <returns>The icon in the form MudBlazor renders, or an empty string for an unknown name.</returns>
|
||||
public static string GetIcon(string value)
|
||||
{
|
||||
var name = value.TrimStart('@');
|
||||
if (name.StartsWith(LUCIDE_PREFIX, StringComparison.Ordinal))
|
||||
return LucideIconRegistry.TryGet(name[LUCIDE_PREFIX.Length..], out var lucideIcon) ? lucideIcon : string.Empty;
|
||||
|
||||
return MudBlazorIconRegistry.TryGetSvg(name, out var svg) ? svg : string.Empty;
|
||||
}
|
||||
|
||||
|
||||
public static Size GetComponentSize(string value, Size fallback) => Enum.TryParse<Size>(value, out var size) ? size : fallback;
|
||||
public static Justify? GetJustify(string value) => Enum.TryParse<Justify>(value, out var justify) ? justify : null;
|
||||
public static AlignItems? GetItemsAlignment(string value) => Enum.TryParse<AlignItems>(value, out var alignment) ? alignment : null;
|
||||
|
||||
+25
-26
@@ -38,32 +38,31 @@ public static class AssistantComponentTypeExtensions
|
||||
|
||||
public string Icon => type switch
|
||||
{
|
||||
AssistantComponentType.BUTTON => MudBlazor.Icons.Material.Filled.AdsClick,
|
||||
AssistantComponentType.BUTTON_GROUP => MudBlazor.Icons.Material.Filled.LinearScale,
|
||||
AssistantComponentType.DROPDOWN => MudBlazor.Icons.Material.Filled.Rule,
|
||||
AssistantComponentType.PROVIDER_SELECTION => MudBlazor.Icons.Material.Filled.Memory,
|
||||
AssistantComponentType.PROFILE_SELECTION => MudBlazor.Icons.Material.Filled.Badge,
|
||||
AssistantComponentType.SWITCH => MudBlazor.Icons.Material.Filled.ToggleOn,
|
||||
AssistantComponentType.HEADING => MudBlazor.Icons.Material.Filled.Title,
|
||||
AssistantComponentType.TEXT => MudBlazor.Icons.Material.Filled.TextFields,
|
||||
AssistantComponentType.TEXT_AREA => MudBlazor.Icons.Material.Filled.Wysiwyg,
|
||||
AssistantComponentType.LIST => MudBlazor.Icons.Material.Filled.List,
|
||||
AssistantComponentType.WEB_CONTENT_READER => MudBlazor.Icons.Material.Filled.Public,
|
||||
AssistantComponentType.FILE_CONTENT_READER => MudBlazor.Icons.Material.Filled.AttachFile,
|
||||
AssistantComponentType.FILE_ATTACHMENTS => MudBlazor.Icons.Material.Filled.AttachFile,
|
||||
AssistantComponentType.IMAGE => MudBlazor.Icons.Material.Filled.Image,
|
||||
AssistantComponentType.COLOR_PICKER => MudBlazor.Icons.Material.Filled.Palette,
|
||||
AssistantComponentType.DATE_PICKER => MudBlazor.Icons.Material.Filled.CalendarMonth,
|
||||
AssistantComponentType.DATE_RANGE_PICKER => MudBlazor.Icons.Material.Filled.DateRange,
|
||||
AssistantComponentType.TIME_PICKER => MudBlazor.Icons.Material.Filled.Schedule,
|
||||
AssistantComponentType.LAYOUT_ITEM => MudBlazor.Icons.Material.Filled.DashboardCustomize,
|
||||
AssistantComponentType.LAYOUT_GRID => MudBlazor.Icons.Material.Filled.GridView,
|
||||
AssistantComponentType.LAYOUT_PAPER => MudBlazor.Icons.Material.Filled.Inbox,
|
||||
AssistantComponentType.LAYOUT_STACK => MudBlazor.Icons.Material.Filled.Layers,
|
||||
AssistantComponentType.LAYOUT_ACCORDION => MudBlazor.Icons.Material.Filled.CalendarViewDay,
|
||||
AssistantComponentType.LAYOUT_ACCORDION_SECTION => MudBlazor.Icons.Material.Filled.HorizontalSplit,
|
||||
AssistantComponentType.FORM => MudBlazor.Icons.Material.Filled.AccountTree,
|
||||
_ => MudBlazor.Icons.Material.Filled.AccountTree,
|
||||
AssistantComponentType.BUTTON => AppIcons.COMPONENT_BUTTON,
|
||||
AssistantComponentType.BUTTON_GROUP => AppIcons.COMPONENT_BUTTON_GROUP,
|
||||
AssistantComponentType.DROPDOWN => AppIcons.COMPONENT_DROPDOWN,
|
||||
AssistantComponentType.PROVIDER_SELECTION => AppIcons.LLM_PROVIDER,
|
||||
AssistantComponentType.PROFILE_SELECTION => AppIcons.PROFILE,
|
||||
AssistantComponentType.SWITCH => AppIcons.SWITCH,
|
||||
AssistantComponentType.HEADING => AppIcons.HEADING,
|
||||
AssistantComponentType.TEXT => AppIcons.TEXT_INPUT,
|
||||
AssistantComponentType.TEXT_AREA => AppIcons.TEXT_AREA,
|
||||
AssistantComponentType.LIST => AppIcons.LIST,
|
||||
AssistantComponentType.WEB_CONTENT_READER => AppIcons.WEB,
|
||||
AssistantComponentType.FILE_CONTENT_READER => AppIcons.ATTACH_FILE,
|
||||
AssistantComponentType.FILE_ATTACHMENTS => AppIcons.ATTACH_FILE,
|
||||
AssistantComponentType.IMAGE => AppIcons.IMAGE,
|
||||
AssistantComponentType.COLOR_PICKER => AppIcons.COLOR,
|
||||
AssistantComponentType.DATE_PICKER => AppIcons.DATE,
|
||||
AssistantComponentType.DATE_RANGE_PICKER => AppIcons.DATE_RANGE,
|
||||
AssistantComponentType.TIME_PICKER => AppIcons.TIME,
|
||||
AssistantComponentType.LAYOUT_ITEM => AppIcons.COMPONENT_LAYOUT_ITEM,
|
||||
AssistantComponentType.LAYOUT_GRID => AppIcons.ASSISTANT_COMPONENT_GRID,
|
||||
AssistantComponentType.LAYOUT_PAPER => AppIcons.COMPONENT_LAYOUT_PAPER,
|
||||
AssistantComponentType.LAYOUT_STACK => AppIcons.COMPONENT_LAYOUT_STACK,
|
||||
AssistantComponentType.LAYOUT_ACCORDION => AppIcons.COMPONENT_ACCORDION,
|
||||
AssistantComponentType.LAYOUT_ACCORDION_SECTION => AppIcons.ASSISTANT_COMPONENT_ACCORDION_SECTION,
|
||||
_ => AppIcons.ASSISTANT_COMPONENTS,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using AIStudio.Tools.PluginSystem.Assistants.Icons;
|
||||
using Lua;
|
||||
|
||||
namespace AIStudio.Tools.PluginSystem.Assistants.DataModel;
|
||||
@@ -105,5 +104,5 @@ public sealed class AssistantSwitch : StatefulAssistantComponentBase
|
||||
|
||||
public static Color GetColor(string colorString) => Enum.TryParse<Color>(colorString, out var color) ? color : Color.Inherit;
|
||||
public Placement GetLabelPlacement() => Enum.TryParse<Placement>(this.LabelPlacement, out var placement) ? placement : Placement.Right;
|
||||
public string GetIconSvg() => MudBlazorIconRegistry.TryGetSvg(this.Icon, out var svg) ? svg : string.Empty;
|
||||
public string GetIcon() => AssistantComponentPropHelper.GetIcon(this.Icon);
|
||||
}
|
||||
+20
-16
@@ -41,28 +41,32 @@ public static class PluginAssistantSecurityResolver
|
||||
private static string GetAvailabilityIcon(bool requiresAudit, bool hasAudit, bool hasHashMismatch, bool isBlocked, bool canOverride)
|
||||
{
|
||||
if (hasHashMismatch)
|
||||
return MudBlazor.Icons.Material.Filled.Warning;
|
||||
return AppIcons.WARNING;
|
||||
if (requiresAudit)
|
||||
return MudBlazor.Icons.Material.Filled.GppMaybe;
|
||||
return AppIcons.SECURITY_WARNING;
|
||||
if (!hasAudit)
|
||||
return MudBlazor.Icons.Material.Filled.HelpOutline;
|
||||
return AppIcons.UNKNOWN;
|
||||
if (isBlocked)
|
||||
return MudBlazor.Icons.Material.Filled.Lock;
|
||||
return AppIcons.LOCK;
|
||||
if (canOverride)
|
||||
return MudBlazor.Icons.Material.Filled.ReportProblem;
|
||||
return AppIcons.WARNING;
|
||||
|
||||
return MudBlazor.Icons.Material.Filled.LockOpen;
|
||||
return AppIcons.UNLOCK;
|
||||
}
|
||||
|
||||
// ReSharper disable UnusedParameter.Local
|
||||
private static string GetSecurityBadgeIcon(bool requiresAudit, bool hasAudit, bool hasHashMismatch, bool isBlocked, bool canOverride)
|
||||
{
|
||||
if (hasHashMismatch)
|
||||
return MudBlazor.Icons.Material.Filled.RemoveModerator;
|
||||
return AppIcons.AUDIT_MISMATCH;
|
||||
if (!hasAudit)
|
||||
return MudBlazor.Icons.Material.Filled.AddModerator;
|
||||
return AppIcons.SECURITY_NOT_AUDITED;
|
||||
|
||||
return MudBlazor.Icons.Material.Filled.Security;
|
||||
// An audit below the required minimum level never shows the check mark of a passed audit:
|
||||
if (isBlocked || canOverride)
|
||||
return AppIcons.SECURITY_AUDIT_FAILED;
|
||||
|
||||
return AppIcons.SECURITY_AUDIT_PASSED;
|
||||
}
|
||||
// ReSharper restore UnusedParameter.Local
|
||||
|
||||
@@ -113,12 +117,12 @@ public static class PluginAssistantSecurityResolver
|
||||
StatusLabel = TB("Unlocked"),
|
||||
SourceLabel = TB("Approved by your organization"),
|
||||
SourceColor = Color.Success,
|
||||
SourceIcon = MudBlazor.Icons.Material.Filled.Business,
|
||||
BadgeIcon = MudBlazor.Icons.Material.Filled.Business,
|
||||
SourceIcon = AppIcons.ORGANIZATION,
|
||||
BadgeIcon = AppIcons.ORGANIZATION,
|
||||
Headline = enterpriseHeadline,
|
||||
Description = TB("The current plugin hash matches an enterprise-managed approval. No manual security audit is required for activation or usage."),
|
||||
StatusColor = Color.Success,
|
||||
StatusIcon = MudBlazor.Icons.Material.Filled.VerifiedUser,
|
||||
StatusIcon = AppIcons.TRUSTED,
|
||||
ActionLabel = TB("Open Security Details"),
|
||||
};
|
||||
}
|
||||
@@ -161,7 +165,7 @@ public static class PluginAssistantSecurityResolver
|
||||
StatusLabel = GetAvailabilityLabel(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false),
|
||||
SourceLabel = TB("No Approval"),
|
||||
SourceColor = Color.Default,
|
||||
SourceIcon = MudBlazor.Icons.Material.Filled.HelpOutline,
|
||||
SourceIcon = AppIcons.UNKNOWN,
|
||||
BadgeIcon = GetSecurityBadgeIcon(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false),
|
||||
Headline = requiresAudit ? TB("This assistant is currently locked.") : TB("This assistant currently has no stored audit."),
|
||||
Description = requiresAudit
|
||||
@@ -200,7 +204,7 @@ public static class PluginAssistantSecurityResolver
|
||||
StatusLabel = GetAvailabilityLabel(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false),
|
||||
SourceLabel = TB("No Approval"),
|
||||
SourceColor = Color.Default,
|
||||
SourceIcon = MudBlazor.Icons.Material.Filled.Warning,
|
||||
SourceIcon = AppIcons.WARNING,
|
||||
BadgeIcon = GetSecurityBadgeIcon(requiresAudit, hasAudit, hasHashMismatch, isBlocked, canOverride: false),
|
||||
Headline = requiresAudit ? TB("This assistant is locked until it is audited again.") : TB("This assistant changed after its last audit."),
|
||||
Description = requiresAudit
|
||||
@@ -242,7 +246,7 @@ public static class PluginAssistantSecurityResolver
|
||||
StatusLabel = GetAvailabilityLabel(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride),
|
||||
SourceLabel = TB("User Audit"),
|
||||
SourceColor = auditLevel.Color,
|
||||
SourceIcon = MudBlazor.Icons.Material.Filled.Verified,
|
||||
SourceIcon = AppIcons.SECURITY_AUDIT_FAILED,
|
||||
BadgeIcon = GetSecurityBadgeIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlockedByMinimum, canOverride),
|
||||
Headline = isBlockedByMinimum
|
||||
? TB("This assistant is currently locked.")
|
||||
@@ -287,7 +291,7 @@ public static class PluginAssistantSecurityResolver
|
||||
StatusLabel = GetAvailabilityLabel(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false),
|
||||
SourceLabel = TB("User Audit"),
|
||||
SourceColor = auditLevelDefault.Color,
|
||||
SourceIcon = MudBlazor.Icons.Material.Filled.Verified,
|
||||
SourceIcon = AppIcons.SECURITY_AUDIT_PASSED,
|
||||
BadgeIcon = GetSecurityBadgeIcon(requiresAudit: false, hasAudit, hasHashMismatch: false, isBlocked: false, canOverride: false),
|
||||
Headline = TB("This assistant is currently unlocked."),
|
||||
Description = string.Format(TB("The stored audit matches the current plugin code and meets your required minimum level '{0}'."), auditSettings.MinimumLevel.Name),
|
||||
|
||||
+5
-5
@@ -46,18 +46,18 @@ public sealed class PluginAssistantSecurityState
|
||||
public bool CanStartAssistant { get; init; }
|
||||
public string AuditLabel { get; init; } = string.Empty;
|
||||
public Color AuditColor { get; init; } = Color.Info;
|
||||
public string AuditIcon { get; init; } = MudBlazor.Icons.Material.Filled.HelpOutline;
|
||||
public string AuditIcon { get; init; } = AppIcons.UNKNOWN;
|
||||
public string AvailabilityLabel { get; init; } = string.Empty;
|
||||
public Color AvailabilityColor { get; init; } = Color.Info;
|
||||
public string AvailabilityIcon { get; init; } = MudBlazor.Icons.Material.Filled.Lock;
|
||||
public string AvailabilityIcon { get; init; } = AppIcons.LOCK;
|
||||
public string StatusLabel { get; init; } = string.Empty;
|
||||
public string SourceLabel { get; init; } = string.Empty;
|
||||
public Color SourceColor { get; init; } = Color.Info;
|
||||
public string SourceIcon { get; init; } = MudBlazor.Icons.Material.Filled.Info;
|
||||
public string SourceIcon { get; init; } = AppIcons.INFO;
|
||||
public string Headline { get; init; } = string.Empty;
|
||||
public string Description { get; init; } = string.Empty;
|
||||
public Color StatusColor { get; init; } = Color.Info;
|
||||
public string StatusIcon { get; init; } = MudBlazor.Icons.Material.Filled.Lock;
|
||||
public string StatusIcon { get; init; } = AppIcons.LOCK;
|
||||
public string ActionLabel { get; init; } = string.Empty;
|
||||
public string BadgeIcon { get; init; } = MudBlazor.Icons.Material.Outlined.Shield;
|
||||
public string BadgeIcon { get; init; } = AppIcons.SECURITY;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ public abstract partial class PluginBase
|
||||
{
|
||||
private const string DEFAULT_ICON_SVG =
|
||||
"""
|
||||
<svg height="1.5em" width="1.5em" viewBox="0 0 24 24" fill="#1f1f1f"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M19 13h-2V7h-6V5c0-.28-.22-.5-.5-.5s-.5.22-.5.5v2H4l.01 2.12C5.76 9.8 7 11.51 7 13.5c0 1.99-1.25 3.7-3 4.38V20h2.12c.68-1.75 2.39-3 4.38-3 1.99 0 3.7 1.25 4.38 3H17v-6h2c.28 0 .5-.22.5-.5s-.22-.5-.5-.5z" opacity=".3"/><path d="M19 11V7c0-1.1-.9-2-2-2h-4c0-1.38-1.12-2.5-2.5-2.5S8 3.62 8 5H4c-1.1 0-1.99.9-1.99 2v3.8h.29c1.49 0 2.7 1.21 2.7 2.7s-1.21 2.7-2.7 2.7H2V20c0 1.1.9 2 2 2h3.8v-.3c0-1.49 1.21-2.7 2.7-2.7s2.7 1.21 2.7 2.7v.3H17c1.1 0 2-.9 2-2v-4c1.38 0 2.5-1.12 2.5-2.5S20.38 11 19 11zm0 3h-2v6h-2.12c-.68-1.75-2.39-3-4.38-3-1.99 0-3.7 1.25-4.38 3H4v-2.12c1.75-.68 3-2.39 3-4.38 0-1.99-1.24-3.7-2.99-4.38L4 7h6V5c0-.28.22-.5.5-.5s.5.22.5.5v2h6v6h2c.28 0 .5.22.5.5s-.22.5-.5.5z"/></svg>
|
||||
<svg height="1.5em" width="1.5em" viewBox="0 0 24 24" fill="none" stroke="#1f1f1f" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22v-5"/><path d="M15 8V2"/><path d="M17 8a1 1 0 0 1 1 1v4a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1z"/><path d="M9 8V2"/></svg>
|
||||
""";
|
||||
|
||||
private static readonly string DEFAULT_ICON_DATA_URL = CreateDefaultIconDataUrl();
|
||||
|
||||
@@ -86,7 +86,7 @@ public sealed class AugmentationOne : IAugmentationProcess
|
||||
// The user switched this check on. Continuing without it silently would hide
|
||||
// that the answer rests on unfiltered passages:
|
||||
//
|
||||
await MessageBus.INSTANCE.SendWarning(new(Icons.Material.Filled.FactCheck, TB("The check of which passages fit your question failed. This answer uses all passages that were found.")));
|
||||
await MessageBus.INSTANCE.SendWarning(new(AppIcons.PASSAGE_RELEVANCE_CHECK, TB("The check of which passages fit your question failed. This answer uses all passages that were found.")));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -111,7 +111,7 @@ public sealed class AugmentationOne : IAugmentationProcess
|
||||
// and each one may miss something else.
|
||||
//
|
||||
if (selection.LeftOutCount > 0)
|
||||
await MessageBus.INSTANCE.SendWarning(new(Icons.Material.Filled.ContentCut, string.Format(TB("Not every passage found in your data sources fits into what the selected model can read. This answer had to do without {0} of them. To give the AI every passage, switch on Semantic Search for this chat, lower the token limit of your data sources, or choose fewer data sources."), selection.LeftOutCount.CompactCount())));
|
||||
await MessageBus.INSTANCE.SendWarning(new(AppIcons.CONTENT_SHORTENED, string.Format(TB("Not every passage found in your data sources fits into what the selected model can read. This answer had to do without {0} of them. To give the AI every passage, switch on Semantic Search for this chat, lower the token limit of your data sources, or choose fewer data sources."), selection.LeftOutCount.CompactCount())));
|
||||
|
||||
//
|
||||
// Add the augmented data to the chat thread, as the very last step: the caller restricts
|
||||
|
||||
@@ -54,7 +54,7 @@ public sealed class PromptInjectionGuardService(
|
||||
{
|
||||
logger.LogError("Could not check {SourceKind} '{SourceLabel}' for prompt injections. The content is used unchanged.", source.Kind, source.Label);
|
||||
await MessageBus.INSTANCE.SendWarning(new(
|
||||
Icons.Material.Filled.GppMaybe,
|
||||
AppIcons.SECURITY_WARNING,
|
||||
string.Format(TB("AI Studio could not check '{0}' for prompt injections. The content is used as it is."), source.NotificationLabel)));
|
||||
|
||||
return text;
|
||||
@@ -106,7 +106,7 @@ public sealed class PromptInjectionGuardService(
|
||||
var sources = texts.Select(x => x.Source).Distinct().ToList();
|
||||
logger.LogError("Could not check {SourceCount} content source(s) for prompt injections. The content is used unchanged. Sources: {SourceLabels}", sources.Count, string.Join(", ", sources.Select(x => $"{x.Kind} '{x.Label}'")));
|
||||
await MessageBus.INSTANCE.SendWarning(new(
|
||||
Icons.Material.Filled.GppMaybe,
|
||||
AppIcons.SECURITY_WARNING,
|
||||
sources.Count is 1
|
||||
? string.Format(TB("AI Studio could not check '{0}' for prompt injections. The content is used as it is."), sources[0].NotificationLabel)
|
||||
: string.Format(TB("AI Studio could not check {0} sources for prompt injections. The content is used as it is."), sources.Count)));
|
||||
@@ -293,7 +293,7 @@ public sealed class PromptInjectionGuardService(
|
||||
results.Count);
|
||||
|
||||
await MessageBus.INSTANCE.SendWarning(new(
|
||||
Icons.Material.Filled.GppMaybe,
|
||||
AppIcons.SECURITY_WARNING,
|
||||
results.Count is 1
|
||||
? string.Format(TB("AI Studio removed suspicious instructions from '{0}' before using it."), results[0].Source.NotificationLabel)
|
||||
: string.Format(TB("AI Studio removed suspicious instructions from {0} sources before using them."), results.Count)));
|
||||
|
||||
@@ -217,7 +217,7 @@ public sealed class GlobalShortcutService : BackgroundService, IMessageBusReceiv
|
||||
{
|
||||
this.localFallbackWarningShown = true;
|
||||
await this.messageBus.SendWarning(new(
|
||||
Icons.Material.Filled.Keyboard,
|
||||
AppIcons.KEYBOARD_SHORTCUT,
|
||||
TB("The voice recording shortcut currently works only while AI Studio is focused.")));
|
||||
}
|
||||
}
|
||||
@@ -236,9 +236,9 @@ public sealed class GlobalShortcutService : BackgroundService, IMessageBusReceiv
|
||||
result.ErrorMessage);
|
||||
|
||||
if (result.Cancelled)
|
||||
await this.messageBus.SendWarning(new(Icons.Material.Filled.Keyboard, userMessage));
|
||||
await this.messageBus.SendWarning(new(AppIcons.KEYBOARD_SHORTCUT, userMessage));
|
||||
else
|
||||
await this.messageBus.SendError(new(Icons.Material.Filled.Keyboard, userMessage));
|
||||
await this.messageBus.SendError(new(AppIcons.KEYBOARD_SHORTCUT, userMessage));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -327,7 +327,7 @@ internal sealed class DocumentRunProgress(IndexedRunContext context, int totalDo
|
||||
|
||||
// Once per kind of failure and pass, not once per document or step:
|
||||
if (context.Pass.TryMarkReported(providerFailure.FailureReason))
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.CloudOff, providerFailure.UserMessage));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.PROVIDER_ERROR, providerFailure.UserMessage));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ public sealed class LocalIndexSearchService(SettingsManager settingsManager, Rus
|
||||
return;
|
||||
}
|
||||
|
||||
await MessageBus.INSTANCE.SendWarning(new(Icons.Material.Filled.SearchOff, userMessage));
|
||||
await MessageBus.INSTANCE.SendWarning(new(AppIcons.RETRIEVAL_GAP, userMessage));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -58,7 +58,7 @@ public sealed class PandocAvailabilityService(RustService rustService, IDialogSe
|
||||
{
|
||||
this.Logger.LogError("Pandoc is not available after installation attempt.");
|
||||
if (showErrorMessage)
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Cancel, TB("AI Studio needs Pandoc for this, but it is not available.")));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.PANDOC_UNAVAILABLE, TB("AI Studio needs Pandoc for this, but it is not available.")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,9 +42,9 @@ public sealed partial class RustService
|
||||
finally
|
||||
{
|
||||
if (succeeded)
|
||||
await MessageBus.INSTANCE.SendSuccess(new(Icons.Material.Filled.ContentCopy, message));
|
||||
await MessageBus.INSTANCE.SendSuccess(new(AppIcons.COPY, message));
|
||||
else
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.ContentCopy, message));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.COPY, message));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,7 @@ public sealed class UpdateService : BackgroundService, IMessageBusReceiver
|
||||
|
||||
if (notifyUserWhenNoUpdate)
|
||||
{
|
||||
await this.messageBus.SendError(new(Icons.Material.Filled.Error, TB("Failed to check for updates. Please try again later.")));
|
||||
await this.messageBus.SendError(new(AppIcons.ERROR, TB("Failed to check for updates. Please try again later.")));
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -127,7 +127,7 @@ public sealed class UpdateService : BackgroundService, IMessageBusReceiver
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
await this.messageBus.SendError(new(Icons.Material.Filled.Error, TB("Failed to install update automatically. Please try again manually.")));
|
||||
await this.messageBus.SendError(new(AppIcons.ERROR, TB("Failed to install update automatically. Please try again manually.")));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -137,7 +137,7 @@ public sealed class UpdateService : BackgroundService, IMessageBusReceiver
|
||||
{
|
||||
if (notifyUserWhenNoUpdate)
|
||||
{
|
||||
await this.messageBus.SendInfo(new(Icons.Material.Filled.Update, TB("No update found.")));
|
||||
await this.messageBus.SendInfo(new(AppIcons.APP_UPDATE, TB("No update found.")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ public static class SourceDocumentLocationExtensions
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.LogWarning(e, "Could not open a source document.");
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Description, TB("Could not open the document.")));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.DOCUMENT, TB("Could not open the document.")));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public static class SourceDocumentLocationExtensions
|
||||
return;
|
||||
|
||||
var issue = string.IsNullOrWhiteSpace(response.Issue) ? TB("Unknown error") : response.Issue;
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Description, string.Format(TB("Could not open the document: {0}"), issue)));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.DOCUMENT, string.Format(TB("Could not open the document: {0}"), issue)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -69,7 +69,7 @@ public static class SourceDocumentLocationExtensions
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.LogWarning(e, "Could not show a source document in the file manager.");
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.FolderOpen, TB("Could not open the file location.")));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.FOLDER_OPEN, TB("Could not open the file location.")));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public static class SourceDocumentLocationExtensions
|
||||
return;
|
||||
|
||||
var issue = string.IsNullOrWhiteSpace(response.Issue) ? TB("Unknown error") : response.Issue;
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.FolderOpen, string.Format(TB("Could not open the file location: {0}"), issue)));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.FOLDER_OPEN, string.Format(TB("Could not open the file location: {0}"), issue)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,6 @@ public static class ToolCallingMessages
|
||||
/// </remarks>
|
||||
/// <param name="statusCode">The status code the provider answered with.</param>
|
||||
public static async Task SendToolCallingRequestFailedAsync(int statusCode) => await MessageBus.INSTANCE.SendError(new(
|
||||
Icons.Material.Filled.Build,
|
||||
AppIcons.TOOL,
|
||||
string.Format(TB("The tool calling request failed with status code {0}. See the logs for details."), statusCode)));
|
||||
}
|
||||
@@ -65,7 +65,7 @@ public interface IToolImplementation
|
||||
public ValueTask<string> ResolveSystemPromptInstructionsAsync(ToolDefinition definition, ToolResolutionContext context, CancellationToken token = default) =>
|
||||
ValueTask.FromResult(definition.SystemPromptInstructions);
|
||||
|
||||
public string Icon => Icons.Material.Filled.Build;
|
||||
public string Icon => AppIcons.TOOL;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this tool exists in this installation right now.
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ public sealed class CountMailsTool(SettingsManager settingsManager, MailboxRetri
|
||||
.OptionalEnum(GROUP_BY_ARGUMENT, $"Optional: break the number of each mailbox down by the folders the mails lie in, or by their senders. Shows the {MAX_GROUPS} largest groups. Leave it out for the totals only.", GROUP_BY_VALUES)
|
||||
.Build();
|
||||
|
||||
public string Icon => Icons.Material.Filled.Numbers;
|
||||
public string Icon => AppIcons.MAIL_COUNT;
|
||||
|
||||
// Only while both previews are switched on, the one for local RAG and the one for mailboxes:
|
||||
public bool IsAvailable => retrievalService.AreMailboxesEnabled;
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ public sealed class MailboxToolCollection : IToolCollection
|
||||
DescriptionForLLM = "Search, read, and count the mails in the mailboxes of the user, including their attachments. AI Studio keeps the mailboxes in a local index; nothing in a mailbox changes.",
|
||||
};
|
||||
|
||||
public string Icon => Icons.Material.Filled.Mail;
|
||||
public string Icon => AppIcons.MAILBOX;
|
||||
|
||||
public string GetDisplayName() => TB("Mailboxes");
|
||||
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ public sealed class ReadMailTool(SettingsManager settingsManager, MailboxRetriev
|
||||
public ValueTask<ToolFunctionDefinition?> ResolveFunctionAsync(ToolDefinition definition, ToolResolutionContext context, CancellationToken token = default) =>
|
||||
ValueTask.FromResult(retrievalService.GetReadableMailboxes(context.ProviderConfidence).Count == 0 ? null : definition.Function);
|
||||
|
||||
public string Icon => Icons.Material.Filled.MarkEmailRead;
|
||||
public string Icon => AppIcons.MAIL_READ;
|
||||
|
||||
// Only while both previews are switched on, the one for local RAG and the one for mailboxes:
|
||||
public bool IsAvailable => retrievalService.AreMailboxesEnabled;
|
||||
|
||||
+1
-1
@@ -167,7 +167,7 @@ public sealed class SearchMailsTool(SettingsManager settingsManager, MailboxRetr
|
||||
.Where(mailbox => mailbox.MaxMatches > 0)
|
||||
.ToList();
|
||||
|
||||
public string Icon => Icons.Material.Filled.Mail;
|
||||
public string Icon => AppIcons.MAIL_SEARCH;
|
||||
|
||||
// Only while both previews are switched on, the one for local RAG and the one for mailboxes:
|
||||
public bool IsAvailable => retrievalService.AreMailboxesEnabled;
|
||||
|
||||
+1
-1
@@ -65,7 +65,7 @@ public sealed class CalculateTool(SettingsManager settingsManager, MathComputati
|
||||
},
|
||||
};
|
||||
|
||||
public string Icon => Icons.Material.Filled.Calculate;
|
||||
public string Icon => AppIcons.MATHEMATICS;
|
||||
|
||||
public bool IsAvailable => PreviewFeatures.PRE_MATHEMATICS_2026.IsEnabled(settingsManager);
|
||||
|
||||
|
||||
+1
-1
@@ -111,7 +111,7 @@ public sealed class ComputeSymbolicallyTool(SettingsManager settingsManager, Mat
|
||||
},
|
||||
};
|
||||
|
||||
public string Icon => Icons.Material.Filled.Functions;
|
||||
public string Icon => AppIcons.TOOL_SYMBOLIC_MATH;
|
||||
|
||||
public bool IsAvailable => PreviewFeatures.PRE_MATHEMATICS_2026.IsEnabled(settingsManager);
|
||||
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ public sealed class MathematicsToolCollection : IToolCollection
|
||||
DescriptionForLLM = "Calculate exactly or to a stated number of digits, and work with formulas: simplify, factor, differentiate, integrate, take limits, and solve equations. Everything is computed locally, and each result is checked numerically where possible.",
|
||||
};
|
||||
|
||||
public string Icon => Icons.Material.Filled.Calculate;
|
||||
public string Icon => AppIcons.MATHEMATICS;
|
||||
|
||||
public string GetDisplayName() => TB("Mathematics");
|
||||
|
||||
|
||||
+2
-2
@@ -95,7 +95,7 @@ public sealed class ReadWebPageTool(WebPageRetrievalService webPageRetrievalServ
|
||||
},
|
||||
};
|
||||
|
||||
public string Icon => Icons.Material.Filled.Article;
|
||||
public string Icon => AppIcons.READ_WEB_PAGE;
|
||||
|
||||
public bool ReturnsUntrustedExternalContent => true;
|
||||
|
||||
@@ -724,7 +724,7 @@ public sealed class ReadWebPageTool(WebPageRetrievalService webPageRetrievalServ
|
||||
providerConfidence);
|
||||
|
||||
await MessageBus.INSTANCE.SendError(new DataErrorMessage(
|
||||
Icons.Material.Filled.Security,
|
||||
AppIcons.PROVIDER_CONFIDENCE,
|
||||
TB("The web page was not loaded because private or VPN web pages require a High-confidence provider.")));
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -326,7 +326,7 @@ public sealed class SemanticSearchTool(SettingsManager settingsManager, DataSour
|
||||
_ => "data source",
|
||||
};
|
||||
|
||||
public string Icon => Icons.Material.Filled.ManageSearch;
|
||||
public string Icon => AppIcons.SEMANTIC_SEARCH;
|
||||
|
||||
// An ERI data source is a server somebody else runs, and even a local document may hold text
|
||||
// written to steer a model:
|
||||
|
||||
+1
-1
@@ -174,7 +174,7 @@ public sealed class WebSearchTool(IEnumerable<IWebSearchBackend> backends, WebPa
|
||||
.Build();
|
||||
}
|
||||
|
||||
public string Icon => Icons.Material.Filled.Language;
|
||||
public string Icon => AppIcons.WEB;
|
||||
|
||||
public bool ReturnsUntrustedExternalContent => true;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ public sealed class ToolInvocationTrace
|
||||
|
||||
public string ToolName { get; set; } = string.Empty;
|
||||
|
||||
public string ToolIcon { get; set; } = Icons.Material.Filled.Build;
|
||||
public string ToolIcon { get; set; } = AppIcons.TOOL;
|
||||
|
||||
public string ToolCallId { get; set; } = string.Empty;
|
||||
|
||||
|
||||
@@ -12,4 +12,4 @@ namespace AIStudio.Tools.ToolCallingSystem;
|
||||
/// <param name="Label">What the user reads on the button.</param>
|
||||
/// <param name="Url">Where the button leads. It opens in the browser, not in AI Studio.</param>
|
||||
/// <param name="Icon">The icon shown before the label.</param>
|
||||
public sealed record ToolSettingsGroupLink(string Label, string Url, string Icon = Icons.Material.Filled.OpenInBrowser);
|
||||
public sealed record ToolSettingsGroupLink(string Label, string Url, string Icon = AppIcons.OPEN_EXTERNAL);
|
||||
@@ -30,7 +30,7 @@ public static class UserFile
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
LOGGER.LogError("Can't load from an empty or null file path.");
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Cancel, TB("The file path is null or empty and the file therefore can not be loaded.")));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.ERROR, TB("The file path is null or empty and the file therefore can not be loaded.")));
|
||||
return FileExtractionResult.Failed(FileExtractionErrorCode.INVALID_REQUEST, "The file path is null or empty.");
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public static class UserFile
|
||||
if (!pandocState.IsAvailable)
|
||||
{
|
||||
LOGGER.LogError("Pandoc is not available after installation attempt, so '{FilePath}' cannot be read.", filePath);
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Cancel, FileExtractionErrorCode.PANDOC_UNAVAILABLE.ToUserMessage(fileName)));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.PANDOC_UNAVAILABLE, FileExtractionErrorCode.PANDOC_UNAVAILABLE.ToUserMessage(fileName)));
|
||||
return FileExtractionResult.Failed(FileExtractionErrorCode.PANDOC_UNAVAILABLE, "Pandoc is required to read this file, but it is not available.");
|
||||
}
|
||||
}
|
||||
@@ -64,19 +64,19 @@ public static class UserFile
|
||||
if (!result.HasUsableContent)
|
||||
{
|
||||
LOGGER.LogError("Reading the file '{FilePath}' failed: code={ErrorCode}, message='{ErrorMessage}'.", filePath, result.ErrorCode, result.ErrorMessage);
|
||||
await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Description, result.ToUserMessage(fileName)));
|
||||
await MessageBus.INSTANCE.SendError(new(AppIcons.DOCUMENT, result.ToUserMessage(fileName)));
|
||||
}
|
||||
else if (result.Outcome is FileExtractionOutcome.PARTIAL)
|
||||
{
|
||||
LOGGER.LogWarning("Parts of the file '{FilePath}' could not be read: pages={FailedPages}.", filePath, string.Join(", ", result.FailedPages));
|
||||
await MessageBus.INSTANCE.SendWarning(new(Icons.Material.Filled.Description, result.ToPartialUserMessage(fileName)));
|
||||
await MessageBus.INSTANCE.SendWarning(new(AppIcons.DOCUMENT, result.ToPartialUserMessage(fileName)));
|
||||
}
|
||||
|
||||
// The file was read correctly, but its extension lies about what it contains:
|
||||
if (result.HasExtensionMismatch)
|
||||
{
|
||||
LOGGER.LogWarning("The file '{FilePath}' is actually a '{DetectedFormat}'.", filePath, result.DetectedFormat);
|
||||
await MessageBus.INSTANCE.SendWarning(new(Icons.Material.Filled.RuleFolder, result.ToExtensionMismatchUserMessage(fileName)));
|
||||
await MessageBus.INSTANCE.SendWarning(new(AppIcons.FILE_TYPE_MISMATCH, result.ToExtensionMismatchUserMessage(fileName)));
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -45,7 +45,7 @@ public static class FileExtensionValidation
|
||||
if (string.Equals(Path.GetExtension(filePath), ".doc", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
await MessageBus.INSTANCE.SendWarning(new(
|
||||
Icons.Material.Filled.Description,
|
||||
AppIcons.DOCUMENT,
|
||||
TB("This file format is not supported. Please convert the .doc file to .docx (e.g. with Microsoft Word).")));
|
||||
return false;
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public static class FileExtensionValidation
|
||||
if (FileTypes.IsAllowedPath(filePath, FileTypes.EXECUTABLES))
|
||||
{
|
||||
await MessageBus.INSTANCE.SendError(new(
|
||||
Icons.Material.Filled.AppBlocking,
|
||||
AppIcons.EXECUTABLE_BLOCKED,
|
||||
TB("Executables are not allowed")));
|
||||
return false;
|
||||
}
|
||||
@@ -65,7 +65,7 @@ public static class FileExtensionValidation
|
||||
// In this use case, we cannot guarantee that a provider is selected yet:
|
||||
case UseCase.DIRECTLY_LOADING_CONTENT:
|
||||
await MessageBus.INSTANCE.SendWarning(new(
|
||||
Icons.Material.Filled.ImageNotSupported,
|
||||
AppIcons.IMAGE_NOT_SUPPORTED,
|
||||
TB("Images are not supported at this place")));
|
||||
return false;
|
||||
|
||||
@@ -76,7 +76,7 @@ public static class FileExtensionValidation
|
||||
//
|
||||
case UseCase.ATTACHING_CONTENT when !FileTypes.IsAllowedPath(filePath, FileTypes.MODEL_IMAGE):
|
||||
await MessageBus.INSTANCE.SendWarning(new(
|
||||
Icons.Material.Filled.ImageNotSupported,
|
||||
AppIcons.IMAGE_NOT_SUPPORTED,
|
||||
string.Format(TB("AI Studio cannot give {0} images to an AI model. Please convert the image to JPG or PNG."), Path.GetExtension(filePath).TrimStart('.').ToUpperInvariant())));
|
||||
return false;
|
||||
|
||||
@@ -91,13 +91,13 @@ public static class FileExtensionValidation
|
||||
// We know that images are not supported:
|
||||
case UseCase.ATTACHING_CONTENT:
|
||||
await MessageBus.INSTANCE.SendWarning(new(
|
||||
Icons.Material.Filled.ImageNotSupported,
|
||||
AppIcons.IMAGE_NOT_SUPPORTED,
|
||||
TB("Images are not supported by the selected provider and model")));
|
||||
return false;
|
||||
|
||||
default:
|
||||
await MessageBus.INSTANCE.SendWarning(new(
|
||||
Icons.Material.Filled.ImageNotSupported,
|
||||
AppIcons.IMAGE_NOT_SUPPORTED,
|
||||
TB("Images are not supported yet")));
|
||||
return false;
|
||||
}
|
||||
@@ -106,7 +106,7 @@ public static class FileExtensionValidation
|
||||
if (FileTypes.IsAllowedPath(filePath, FileTypes.VIDEO))
|
||||
{
|
||||
await MessageBus.INSTANCE.SendWarning(new(
|
||||
Icons.Material.Filled.FeaturedVideo,
|
||||
AppIcons.VIDEO,
|
||||
TB("Videos are not supported yet")));
|
||||
return false;
|
||||
}
|
||||
@@ -114,7 +114,7 @@ public static class FileExtensionValidation
|
||||
if (FileTypes.IsAllowedPath(filePath, FileTypes.AUDIO))
|
||||
{
|
||||
await MessageBus.INSTANCE.SendWarning(new(
|
||||
Icons.Material.Filled.AudioFile,
|
||||
AppIcons.AUDIO_FILE,
|
||||
TB("Audio files are not supported yet")));
|
||||
return false;
|
||||
}
|
||||
@@ -123,7 +123,7 @@ public static class FileExtensionValidation
|
||||
return true;
|
||||
|
||||
await MessageBus.INSTANCE.SendWarning(new(
|
||||
Icons.Material.Filled.InsertDriveFile,
|
||||
AppIcons.UNSUPPORTED_FILE_TYPE,
|
||||
TB("Unsupported file type")));
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user