diff --git a/app/MindWork AI Studio/Agents/AgentBase.cs b/app/MindWork AI Studio/Agents/AgentBase.cs
new file mode 100644
index 0000000..191ca27
--- /dev/null
+++ b/app/MindWork AI Studio/Agents/AgentBase.cs
@@ -0,0 +1,109 @@
+using AIStudio.Chat;
+using AIStudio.Provider;
+using AIStudio.Settings;
+using AIStudio.Tools;
+
+// ReSharper disable MemberCanBePrivate.Global
+
+namespace AIStudio.Agents;
+
+public abstract class AgentBase(SettingsManager settingsManager, IJSRuntime jsRuntime, ThreadSafeRandom rng) : IAgent
+{
+ protected SettingsManager SettingsManager { get; init; } = settingsManager;
+
+ protected IJSRuntime JsRuntime { get; init; } = jsRuntime;
+
+ protected ThreadSafeRandom RNG { get; init; } = rng;
+
+ ///
+ /// Represents the type or category of this agent.
+ ///
+ protected abstract Type Type { get; }
+
+ ///
+ /// The name of the agent.
+ ///
+ public abstract string Id { get; }
+
+ ///
+ /// The agent's job description. Will be used for the system prompt.
+ ///
+ protected abstract string JobDescription { get; }
+
+ ///
+ /// Represents the system prompt provided for the agent.
+ ///
+ protected abstract string SystemPrompt(string additionalData);
+
+ #region Implementation of IAgent
+
+ public abstract AIStudio.Settings.Provider? ProviderSettings { get; set; }
+
+ public abstract Task ProcessContext(ChatThread chatThread, IDictionary additionalData);
+
+ public abstract Task ProcessInput(ContentBlock input, IDictionary additionalData);
+
+ public abstract Task MadeDecision(ContentBlock input);
+
+ public abstract IReadOnlyCollection GetContext();
+
+ public abstract IReadOnlyCollection GetAnswers();
+
+ #endregion
+
+ protected ChatThread CreateChatThread(string systemPrompt) => new()
+ {
+ WorkspaceId = Guid.Empty,
+ ChatId = Guid.NewGuid(),
+ Name = string.Empty,
+ Seed = this.RNG.Next(),
+ SystemPrompt = systemPrompt,
+ Blocks = [],
+ };
+
+ protected DateTimeOffset AddUserRequest(ChatThread thread, string request)
+ {
+ var time = DateTimeOffset.Now;
+ thread.Blocks.Add(new ContentBlock
+ {
+ Time = time,
+ ContentType = ContentType.TEXT,
+ Role = ChatRole.USER,
+ Content = new ContentText
+ {
+ Text = request,
+ },
+ });
+
+ return time;
+ }
+
+ protected async Task AddAIResponseAsync(ChatThread thread, DateTimeOffset time)
+ {
+ if(this.ProviderSettings is null)
+ return;
+
+ var providerSettings = this.ProviderSettings.Value;
+ var aiText = new ContentText
+ {
+ // We have to wait for the remote
+ // for the content stream:
+ InitialRemoteWait = true,
+ };
+
+ var resultingContentBlock = new ContentBlock
+ {
+ Time = time,
+ ContentType = ContentType.TEXT,
+ Role = ChatRole.AI,
+ Content = aiText,
+ };
+
+ thread.Blocks.Add(resultingContentBlock);
+
+ // Use the selected provider to get the AI response.
+ // By awaiting this line, we wait for the entire
+ // content to be streamed.
+ await aiText.CreateFromProviderAsync(providerSettings.CreateProvider(), this.JsRuntime, this.SettingsManager, providerSettings.Model, thread);
+ }
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Agents/AgentTextContentCleaner.cs b/app/MindWork AI Studio/Agents/AgentTextContentCleaner.cs
new file mode 100644
index 0000000..83fe48f
--- /dev/null
+++ b/app/MindWork AI Studio/Agents/AgentTextContentCleaner.cs
@@ -0,0 +1,94 @@
+using AIStudio.Chat;
+using AIStudio.Settings;
+using AIStudio.Tools;
+
+namespace AIStudio.Agents;
+
+public sealed class AgentTextContentCleaner(SettingsManager settingsManager, IJSRuntime jsRuntime, ThreadSafeRandom rng) : AgentBase(settingsManager, jsRuntime, rng)
+{
+ private static readonly ContentBlock EMPTY_BLOCK = new()
+ {
+ Content = null,
+ ContentType = ContentType.NONE,
+ Role = ChatRole.AGENT,
+ Time = DateTimeOffset.UtcNow,
+ };
+
+ private readonly List context = new();
+ private readonly List answers = new();
+
+ #region Overrides of AgentBase
+
+ public override Settings.Provider? ProviderSettings { get; set; }
+
+ protected override Type Type => Type.SYSTEM;
+
+ public override string Id => "Text Content Cleaner";
+
+ protected override string JobDescription =>
+ """
+ You receive a Markdown document as input. Your goal is to identify the main content of the document
+ and return it including Markdown formatting. Remove areas that do not belong to the main part of the
+ document. For a blog article, return only the text of the article with its formatting. For a scientific
+ paper, only the contents of the paper. Delete elements of navigation, advertisements, HTML artifacts,
+ cookie banners, etc. If the content contains images, these images remain. The same applies to links.
+ Ensure that links and images are present as valid Markdown:
+
+ - Syntax of links: [link text](URL)
+ - Syntax of images: ![alt text](URL)
+
+ If you find relative links or images with relative paths, correct them to absolute paths. For this
+ purpose, here is the source URL:
+ """;
+
+ protected override string SystemPrompt(string additionalData) => $"{this.JobDescription} `{additionalData}`.";
+
+ ///
+ public override async Task ProcessContext(ChatThread chatThread, IDictionary additionalData)
+ {
+ // We process the last block of the chat thread. Then, we add the result
+ // to the chat thread as the last block:
+ var answer = await this.ProcessInput(chatThread.Blocks[^1], additionalData);
+ chatThread.Blocks.Add(answer);
+
+ this.context.Clear();
+ this.context.AddRange(chatThread.Blocks);
+
+ return chatThread;
+ }
+
+ //
+ public override async Task ProcessInput(ContentBlock input, IDictionary additionalData)
+ {
+ if (input.Content is not ContentText text)
+ return EMPTY_BLOCK;
+
+ if(text.InitialRemoteWait || text.IsStreaming)
+ return EMPTY_BLOCK;
+
+ if(string.IsNullOrWhiteSpace(text.Text))
+ return EMPTY_BLOCK;
+
+ if(!additionalData.TryGetValue("sourceURL", out var sourceURL) || string.IsNullOrWhiteSpace(sourceURL))
+ return EMPTY_BLOCK;
+
+ var thread = this.CreateChatThread(this.SystemPrompt(sourceURL));
+ var time = this.AddUserRequest(thread, text.Text);
+ await this.AddAIResponseAsync(thread, time);
+
+ var answer = thread.Blocks[^1];
+ this.answers.Add(answer);
+ return answer;
+ }
+
+ //
+ public override Task MadeDecision(ContentBlock input) => Task.FromResult(true);
+
+ //
+ public override IReadOnlyCollection GetContext() => this.context;
+
+ //
+ public override IReadOnlyCollection GetAnswers() => this.answers;
+
+ #endregion
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Agents/IAgent.cs b/app/MindWork AI Studio/Agents/IAgent.cs
new file mode 100644
index 0000000..e101f2e
--- /dev/null
+++ b/app/MindWork AI Studio/Agents/IAgent.cs
@@ -0,0 +1,55 @@
+using AIStudio.Chat;
+
+namespace AIStudio.Agents;
+
+public interface IAgent
+{
+ ///
+ /// Gets the name of the agent.
+ ///
+ public string Id { get; }
+
+ ///
+ /// The provider to use for this agent.
+ ///
+ public AIStudio.Settings.Provider? ProviderSettings { get; set; }
+
+ ///
+ /// Processes a chat thread (i.e., context) and returns the updated thread.
+ ///
+ /// The chat thread to process. The thread is the context for the agent.
+ /// Additional data to use for processing the chat thread.
+ /// The updated chat thread. The last content block of the thread is the agent's response.
+ public Task ProcessContext(ChatThread chatThread, IDictionary additionalData);
+
+ ///
+ /// Processes the input content block and returns the agent's response.
+ ///
+ /// The content block to process. It represents the input.
+ /// Additional data to use for processing the input.
+ /// The content block representing the agent's response.
+ public Task ProcessInput(ContentBlock input, IDictionary additionalData);
+
+ ///
+ /// The agent makes a decision based on the input.
+ ///
+ /// The content block to process. Should be a question or a request.
+ ///
+ /// True if a decision has been made based on the input, false otherwise.
+ ///
+ public Task MadeDecision(ContentBlock input);
+
+ ///
+ /// Retrieves the context of the agent.
+ ///
+ /// The collection of content blocks representing the agent's context. This includes the user's and the other agent's messages.
+ public IReadOnlyCollection GetContext();
+
+ ///
+ /// Retrieves the answers from the agent's context.
+ ///
+ ///
+ /// The collection of content blocks representing the answers provided by this agent.
+ ///
+ public IReadOnlyCollection GetAnswers();
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Agents/Type.cs b/app/MindWork AI Studio/Agents/Type.cs
new file mode 100644
index 0000000..559f100
--- /dev/null
+++ b/app/MindWork AI Studio/Agents/Type.cs
@@ -0,0 +1,27 @@
+namespace AIStudio.Agents;
+
+public enum Type
+{
+ ///
+ /// Represents an unspecified agent type.
+ ///
+ UNSPECIFIED = 0,
+
+ ///
+ /// Represents a conversational agent who produces human-like responses and feedback (depending on the context and its job description).
+ /// For example, an expert agent for a specific domain. Answers might be detailed and informative.
+ ///
+ CONVERSATIONAL,
+
+ ///
+ /// Represents a worker agent type who performs tasks and provides information or services (depending on the context and its job description).
+ /// For example, a quality assurance agent who assesses the quality of a product or service. Answers might be short and concise.
+ ///
+ WORKER,
+
+ ///
+ /// Represents the system agent type who processes the input and provides a specific response (depending on the context and its job description).
+ /// For example, a HTML content agent who processes the arbitrary HTML content and provides a structured Markdown response. Answers might be structured and formatted.
+ ///
+ SYSTEM,
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Chat/ChatRole.cs b/app/MindWork AI Studio/Chat/ChatRole.cs
index 2b8712b..339be97 100644
--- a/app/MindWork AI Studio/Chat/ChatRole.cs
+++ b/app/MindWork AI Studio/Chat/ChatRole.cs
@@ -11,6 +11,7 @@ public enum ChatRole
SYSTEM,
USER,
AI,
+ AGENT,
}
///
diff --git a/app/MindWork AI Studio/Components/AssistantBase.razor.cs b/app/MindWork AI Studio/Components/AssistantBase.razor.cs
index a2e46ea..5ef9e70 100644
--- a/app/MindWork AI Studio/Components/AssistantBase.razor.cs
+++ b/app/MindWork AI Studio/Components/AssistantBase.razor.cs
@@ -1,6 +1,7 @@
using AIStudio.Chat;
using AIStudio.Provider;
using AIStudio.Settings;
+using AIStudio.Tools;
using Microsoft.AspNetCore.Components;
@@ -15,7 +16,7 @@ public abstract partial class AssistantBase : ComponentBase
protected IJSRuntime JsRuntime { get; init; } = null!;
[Inject]
- protected Random RNG { get; set; } = null!;
+ protected ThreadSafeRandom RNG { get; init; } = null!;
protected abstract string Title { get; }
diff --git a/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs b/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs
index 244198c..833794a 100644
--- a/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs
+++ b/app/MindWork AI Studio/Components/Blocks/Changelog.Logs.cs
@@ -13,6 +13,7 @@ public partial class Changelog
public static readonly Log[] LOGS =
[
+ new (168, "v0.8.6, build 168 (2024-08-01 19:50 UTC)", "v0.8.6.md"),
new (167, "v0.8.5, build 167 (2024-07-28 16:44 UTC)", "v0.8.5.md"),
new (166, "v0.8.4, build 166 (2024-07-26 06:53 UTC)", "v0.8.4.md"),
new (165, "v0.8.3, build 165 (2024-07-25 13:25 UTC)", "v0.8.3.md"),
diff --git a/app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor b/app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor
new file mode 100644
index 0000000..8b33a12
--- /dev/null
+++ b/app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor
@@ -0,0 +1,31 @@
+
+
+
+ @(this.showWebContentReader ? "Show web content options" : "Hide web content options")
+
+
+
+ @if (this.showWebContentReader)
+ {
+
+
+ @(this.useContentCleanerAgent ? "The content is cleaned using an LLM agent: the main content is extracted, advertisements and other irrelevant things are attempted to be removed; relative links are attempted to be converted into absolute links so that they can be used." : "No content cleaning")
+
+
+
+
+
+ Fetch
+
+
+ @if (this.AgentIsRunning)
+ {
+
+
+
+
+
+
+ }
+ }
+
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor.cs b/app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor.cs
new file mode 100644
index 0000000..56cbd60
--- /dev/null
+++ b/app/MindWork AI Studio/Components/Blocks/ReadWebContent.razor.cs
@@ -0,0 +1,198 @@
+using AIStudio.Agents;
+using AIStudio.Chat;
+using AIStudio.Settings;
+using AIStudio.Tools;
+
+using Microsoft.AspNetCore.Components;
+
+namespace AIStudio.Components.Blocks;
+
+public partial class ReadWebContent : ComponentBase
+{
+ [Inject]
+ private HTMLParser HTMLParser { get; init; } = null!;
+
+ [Inject]
+ private AgentTextContentCleaner AgentTextContentCleaner { get; init; } = null!;
+
+ [Inject]
+ protected SettingsManager SettingsManager { get; set; } = null!;
+
+ [Inject]
+ protected IJSRuntime JsRuntime { get; init; } = null!;
+
+ [Parameter]
+ public string Content { get; set; } = string.Empty;
+
+ [Parameter]
+ public EventCallback ContentChanged { get; set; }
+
+ [Parameter]
+ public Settings.Provider ProviderSettings { get; set; }
+
+ [Parameter]
+ public bool AgentIsRunning { get; set; }
+
+ [Parameter]
+ public EventCallback AgentIsRunningChanged { get; set; }
+
+ [Parameter]
+ public bool Preselect { get; set; }
+
+ [Parameter]
+ public bool PreselectContentCleanerAgent { get; set; }
+
+ private Process process = Process.INSTANCE;
+ private ProcessStepValue processStep;
+
+ private bool showWebContentReader;
+ private bool useContentCleanerAgent;
+ private string providedURL = string.Empty;
+ private bool urlIsValid;
+ private bool isProviderValid;
+
+ private Settings.Provider providerSettings;
+
+ #region Overrides of ComponentBase
+
+ protected override async Task OnInitializedAsync()
+ {
+ if(this.Preselect)
+ this.showWebContentReader = true;
+
+ if(this.PreselectContentCleanerAgent)
+ this.useContentCleanerAgent = true;
+
+ if (this.SettingsManager.ConfigurationData.PreselectAgentTextContentCleanerOptions)
+ this.providerSettings = this.SettingsManager.ConfigurationData.Providers.FirstOrDefault(x => x.Id == this.SettingsManager.ConfigurationData.PreselectedAgentTextContentCleanerProvider);
+ else
+ this.providerSettings = this.ProviderSettings;
+
+ await base.OnInitializedAsync();
+ }
+
+ protected override async Task OnParametersSetAsync()
+ {
+ if (!this.SettingsManager.ConfigurationData.PreselectAgentTextContentCleanerOptions)
+ this.providerSettings = this.ProviderSettings;
+
+ await base.OnParametersSetAsync();
+ }
+
+ #endregion
+
+ private async Task LoadFromWeb()
+ {
+ if(!this.IsReady)
+ return;
+
+ var markdown = string.Empty;
+ try
+ {
+ this.processStep = this.process[ReadWebContentSteps.LOADING];
+ this.StateHasChanged();
+
+ var html = await this.HTMLParser.LoadWebContentHTML(new Uri(this.providedURL));
+
+ this.processStep = this.process[ReadWebContentSteps.PARSING];
+ this.StateHasChanged();
+ markdown = this.HTMLParser.ParseToMarkdown(html);
+
+ if (this.useContentCleanerAgent)
+ {
+ this.AgentTextContentCleaner.ProviderSettings = this.providerSettings;
+ var additionalData = new Dictionary
+ {
+ { "sourceURL", this.providedURL },
+ };
+
+ this.processStep = this.process[ReadWebContentSteps.CLEANING];
+ this.AgentIsRunning = true;
+ await this.AgentIsRunningChanged.InvokeAsync(this.AgentIsRunning);
+ this.StateHasChanged();
+
+ var contentBlock = await this.AgentTextContentCleaner.ProcessInput(new ContentBlock
+ {
+ Time = DateTimeOffset.UtcNow,
+ ContentType = ContentType.TEXT,
+ Role = ChatRole.USER,
+ Content = new ContentText
+ {
+ Text = markdown,
+ },
+ }, additionalData);
+
+ markdown = contentBlock.Content is ContentText text ? text.Text : markdown;
+
+ this.processStep = this.process[ReadWebContentSteps.DONE];
+ this.AgentIsRunning = false;
+ await this.AgentIsRunningChanged.InvokeAsync(this.AgentIsRunning);
+ this.StateHasChanged();
+ }
+ }
+ catch
+ {
+ if (this.AgentIsRunning)
+ {
+ this.processStep = this.process[ReadWebContentSteps.START];
+ this.AgentIsRunning = false;
+ await this.AgentIsRunningChanged.InvokeAsync(this.AgentIsRunning);
+ this.StateHasChanged();
+ }
+ }
+
+ this.Content = markdown;
+ await this.ContentChanged.InvokeAsync(this.Content);
+ }
+
+ private bool IsReady
+ {
+ get
+ {
+ if(!this.urlIsValid)
+ return false;
+
+ if(this.useContentCleanerAgent && !this.isProviderValid)
+ return false;
+
+ return true;
+ }
+ }
+
+ private string? ValidateProvider(bool shouldUseAgent)
+ {
+ if(shouldUseAgent && this.providerSettings == default)
+ {
+ this.isProviderValid = false;
+ return "Please select a provider to use the cleanup agent.";
+ }
+
+ this.isProviderValid = true;
+ return null;
+ }
+
+ private string? ValidateURL(string url)
+ {
+ if(string.IsNullOrWhiteSpace(url))
+ {
+ this.urlIsValid = false;
+ return "Please provide a URL to load the content from.";
+ }
+
+ var urlParsingResult = Uri.TryCreate(url, UriKind.Absolute, out var uriResult);
+ if(!urlParsingResult)
+ {
+ this.urlIsValid = false;
+ return "Please provide a valid URL.";
+ }
+
+ if(uriResult is not { Scheme: "http" or "https" })
+ {
+ this.urlIsValid = false;
+ return "Please provide a valid HTTP or HTTPS URL.";
+ }
+
+ this.urlIsValid = true;
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/Blocks/ReadWebContentSteps.cs b/app/MindWork AI Studio/Components/Blocks/ReadWebContentSteps.cs
new file mode 100644
index 0000000..3dafa01
--- /dev/null
+++ b/app/MindWork AI Studio/Components/Blocks/ReadWebContentSteps.cs
@@ -0,0 +1,10 @@
+namespace AIStudio.Components.Blocks;
+
+public enum ReadWebContentSteps
+{
+ START,
+ LOADING,
+ PARSING,
+ CLEANING,
+ DONE,
+}
diff --git a/app/MindWork AI Studio/Components/Blocks/Workspaces.razor.cs b/app/MindWork AI Studio/Components/Blocks/Workspaces.razor.cs
index 02ef041..19802ef 100644
--- a/app/MindWork AI Studio/Components/Blocks/Workspaces.razor.cs
+++ b/app/MindWork AI Studio/Components/Blocks/Workspaces.razor.cs
@@ -16,13 +16,13 @@ namespace AIStudio.Components.Blocks;
public partial class Workspaces : ComponentBase
{
[Inject]
- private SettingsManager SettingsManager { get; set; } = null!;
+ private SettingsManager SettingsManager { get; init; } = null!;
[Inject]
- private IDialogService DialogService { get; set; } = null!;
+ private IDialogService DialogService { get; init; } = null!;
[Inject]
- public Random RNG { get; set; } = null!;
+ private ThreadSafeRandom RNG { get; init; } = null!;
[Parameter]
public ChatThread? CurrentChatThread { get; set; }
diff --git a/app/MindWork AI Studio/Components/Pages/About.razor b/app/MindWork AI Studio/Components/Pages/About.razor
index 6aa02ba..0f29700 100644
--- a/app/MindWork AI Studio/Components/Pages/About.razor
+++ b/app/MindWork AI Studio/Components/Pages/About.razor
@@ -47,6 +47,8 @@
+
+
diff --git a/app/MindWork AI Studio/Components/Pages/Chat.razor.cs b/app/MindWork AI Studio/Components/Pages/Chat.razor.cs
index d880982..05eae50 100644
--- a/app/MindWork AI Studio/Components/Pages/Chat.razor.cs
+++ b/app/MindWork AI Studio/Components/Pages/Chat.razor.cs
@@ -25,7 +25,7 @@ public partial class Chat : MSGComponentBase, IAsyncDisposable
public IJSRuntime JsRuntime { get; init; } = null!;
[Inject]
- public Random RNG { get; set; } = null!;
+ private ThreadSafeRandom RNG { get; init; } = null!;
[Inject]
public IDialogService DialogService { get; set; } = null!;
diff --git a/app/MindWork AI Studio/Components/Pages/Settings.razor b/app/MindWork AI Studio/Components/Pages/Settings.razor
index 6551a72..0f0e788 100644
--- a/app/MindWork AI Studio/Components/Pages/Settings.razor
+++ b/app/MindWork AI Studio/Components/Pages/Settings.razor
@@ -82,7 +82,7 @@
- Assistants Options
+ Assistant Options
Icon Finder Options
@@ -93,8 +93,11 @@
Translator Options
+
+
+
@if (this.SettingsManager.ConfigurationData.PreselectedTranslationTargetLanguage is CommonLanguages.OTHER)
@@ -117,8 +120,11 @@
Text Summarizer Options
+
+
+
@if (this.SettingsManager.ConfigurationData.PreselectedTextSummarizerTargetLanguage is CommonLanguages.OTHER)
{
@@ -131,5 +137,17 @@
}
+
+ LLM Agent Options
+
+ Text Content Cleaner Agent
+
+
+ Use Case: this agent is used to clean up text content. It extracts the main content, removes advertisements and other irrelevant things,
+ and attempts to convert relative links into absolute links so that they can be used.
+
+
+
+
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor b/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor
index d290541..82f138e 100644
--- a/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor
+++ b/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor
@@ -3,7 +3,12 @@
@using AIStudio.Tools
@inherits AssistantBaseCore
-
+@if (!this.SettingsManager.ConfigurationData.HideWebContentReaderForTextSummarizer)
+{
+
+}
+
+
@@ -31,13 +36,13 @@
}
-
+
@foreach (var provider in this.SettingsManager.ConfigurationData.Providers)
{
}
-
+
Summarize
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor.cs b/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor.cs
index 829206d..9a1b3f8 100644
--- a/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor.cs
+++ b/app/MindWork AI Studio/Components/Pages/TextSummarizer/AssistantTextSummarizer.razor.cs
@@ -24,6 +24,7 @@ public partial class AssistantTextSummarizer : AssistantBaseCore
""";
private string inputText = string.Empty;
+ private bool isAgentRunning;
private CommonLanguages selectedTargetLanguage;
private string customTargetLanguage = string.Empty;
private Complexity selectedComplexity;
diff --git a/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor b/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor
index 8d14032..2b03eca 100644
--- a/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor
+++ b/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor
@@ -3,6 +3,11 @@
@using AIStudio.Tools
@inherits AssistantBaseCore
+@if (!this.SettingsManager.ConfigurationData.HideWebContentReaderForTranslation)
+{
+
+}
+
@(this.liveTranslation ? "Live translation" : "No live translation")
@@ -11,11 +16,11 @@
@if (this.liveTranslation)
{
-
+
}
else
{
-
+
}
@@ -38,13 +43,13 @@ else
}
-
+
@foreach (var provider in this.SettingsManager.ConfigurationData.Providers)
{
}
-
+
Translate
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor.cs b/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor.cs
index 1ae77c1..e21dcd3 100644
--- a/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor.cs
+++ b/app/MindWork AI Studio/Components/Pages/Translation/AssistantTranslation.razor.cs
@@ -20,6 +20,7 @@ public partial class AssistantTranslation : AssistantBaseCore
""";
private bool liveTranslation;
+ private bool isAgentRunning;
private string inputText = string.Empty;
private string inputTextLastTranslation = string.Empty;
private CommonLanguages selectedTargetLanguage;
diff --git a/app/MindWork AI Studio/MindWork AI Studio.csproj b/app/MindWork AI Studio/MindWork AI Studio.csproj
index 9d6605a..a24bc83 100644
--- a/app/MindWork AI Studio/MindWork AI Studio.csproj
+++ b/app/MindWork AI Studio/MindWork AI Studio.csproj
@@ -45,9 +45,11 @@
+
+
diff --git a/app/MindWork AI Studio/Program.cs b/app/MindWork AI Studio/Program.cs
index 1ca814e..5bc114a 100644
--- a/app/MindWork AI Studio/Program.cs
+++ b/app/MindWork AI Studio/Program.cs
@@ -1,4 +1,5 @@
using AIStudio;
+using AIStudio.Agents;
using AIStudio.Components;
using AIStudio.Settings;
using AIStudio.Tools;
@@ -29,7 +30,9 @@ builder.Services.AddSingleton(MessageBus.INSTANCE);
builder.Services.AddSingleton();
builder.Services.AddMudMarkdownClipboardService();
builder.Services.AddSingleton();
-builder.Services.AddSingleton();
+builder.Services.AddSingleton();
+builder.Services.AddTransient();
+builder.Services.AddTransient();
builder.Services.AddHostedService();
builder.Services.AddHostedService();
builder.Services.AddRazorComponents()
diff --git a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs
index 89c6fe0..ffeb255 100644
--- a/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs
+++ b/app/MindWork AI Studio/Provider/Anthropic/ProviderAnthropic.cs
@@ -41,6 +41,7 @@ public sealed class ProviderAnthropic() : BaseProvider("https://api.anthropic.co
{
ChatRole.USER => "user",
ChatRole.AI => "assistant",
+ ChatRole.AGENT => "assistant",
_ => "user",
},
diff --git a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs
index 2f6d1ea..cf29a6d 100644
--- a/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs
+++ b/app/MindWork AI Studio/Provider/Fireworks/ProviderFireworks.cs
@@ -52,6 +52,7 @@ public class ProviderFireworks() : BaseProvider("https://api.fireworks.ai/infere
{
ChatRole.USER => "user",
ChatRole.AI => "assistant",
+ ChatRole.AGENT => "assistant",
ChatRole.SYSTEM => "system",
_ => "user",
diff --git a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs
index 95256fb..c351081 100644
--- a/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs
+++ b/app/MindWork AI Studio/Provider/Mistral/ProviderMistral.cs
@@ -51,6 +51,7 @@ public sealed class ProviderMistral() : BaseProvider("https://api.mistral.ai/v1/
{
ChatRole.USER => "user",
ChatRole.AI => "assistant",
+ ChatRole.AGENT => "assistant",
ChatRole.SYSTEM => "system",
_ => "user",
diff --git a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs
index a18a403..6e4af60 100644
--- a/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs
+++ b/app/MindWork AI Studio/Provider/OpenAI/ProviderOpenAI.cs
@@ -55,6 +55,7 @@ public sealed class ProviderOpenAI() : BaseProvider("https://api.openai.com/v1/"
{
ChatRole.USER => "user",
ChatRole.AI => "assistant",
+ ChatRole.AGENT => "assistant",
ChatRole.SYSTEM => "system",
_ => "user",
diff --git a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs
index 7790d2e..623c3b1 100644
--- a/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs
+++ b/app/MindWork AI Studio/Provider/SelfHosted/ProviderSelfHosted.cs
@@ -44,6 +44,7 @@ public sealed class ProviderSelfHosted(Settings.Provider provider) : BaseProvide
{
ChatRole.USER => "user",
ChatRole.AI => "assistant",
+ ChatRole.AGENT => "assistant",
ChatRole.SYSTEM => "system",
_ => "user",
diff --git a/app/MindWork AI Studio/Settings/DataModel/Data.cs b/app/MindWork AI Studio/Settings/DataModel/Data.cs
index 26639b6..7ed6022 100644
--- a/app/MindWork AI Studio/Settings/DataModel/Data.cs
+++ b/app/MindWork AI Studio/Settings/DataModel/Data.cs
@@ -120,6 +120,21 @@ public sealed class Data
///
public bool PreselectLiveTranslation { get; set; }
+ ///
+ /// Hide the web content reader?
+ ///
+ public bool HideWebContentReaderForTranslation { get; set; }
+
+ ///
+ /// Preselect the web content reader?
+ ///
+ public bool PreselectWebContentReaderForTranslation { get; set; }
+
+ ///
+ /// Preselect the content cleaner agent?
+ ///
+ public bool PreselectContentCleanerAgentForTranslation { get; set; }
+
///
/// Preselect the target language?
///
@@ -173,6 +188,22 @@ public sealed class Data
///
public bool PreselectTextSummarizerOptions { get; set; }
+
+ ///
+ /// Hide the web content reader?
+ ///
+ public bool HideWebContentReaderForTextSummarizer { get; set; }
+
+ ///
+ /// Preselect the web content reader?
+ ///
+ public bool PreselectWebContentReaderForTextSummarizer { get; set; }
+
+ ///
+ /// Preselect the content cleaner agent?
+ ///
+ public bool PreselectContentCleanerAgentForTextSummarizer { get; set; }
+
///
/// Preselect the target language?
///
@@ -199,4 +230,18 @@ public sealed class Data
public string PreselectedTextSummarizerProvider { get; set; } = string.Empty;
#endregion
+
+ #region Agent: Text Content Cleaner Settings
+
+ ///
+ /// Preselect any text content cleaner options?
+ ///
+ public bool PreselectAgentTextContentCleanerOptions { get; set; }
+
+ ///
+ /// Preselect a text content cleaner provider?
+ ///
+ public string PreselectedAgentTextContentCleanerProvider { get; set; } = string.Empty;
+
+ #endregion
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Tools/HTMLParser.cs b/app/MindWork AI Studio/Tools/HTMLParser.cs
new file mode 100644
index 0000000..4f9dca2
--- /dev/null
+++ b/app/MindWork AI Studio/Tools/HTMLParser.cs
@@ -0,0 +1,57 @@
+using System.Net;
+using System.Text;
+
+using HtmlAgilityPack;
+
+using ReverseMarkdown;
+
+namespace AIStudio.Tools;
+
+public sealed class HTMLParser
+{
+ private static readonly Config MARKDOWN_PARSER_CONFIG = new()
+ {
+ UnknownTags = Config.UnknownTagsOption.Bypass,
+ RemoveComments = true,
+ SmartHrefHandling = true
+ };
+
+ ///
+ /// Loads the web content from the specified URL.
+ ///
+ /// The URL of the web page.
+ /// The web content as text.
+ public async Task LoadWebContentText(Uri url)
+ {
+ var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
+ var parser = new HtmlWeb();
+ var doc = await parser.LoadFromWebAsync(url, Encoding.UTF8, new NetworkCredential(), cts.Token);
+ return doc.ParsedText;
+ }
+
+ ///
+ /// Loads the web content from the specified URL and returns it as an HTML string.
+ ///
+ /// The URL of the web page.
+ /// The web content as an HTML string.
+ public async Task LoadWebContentHTML(Uri url)
+ {
+ var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
+ var parser = new HtmlWeb();
+ var doc = await parser.LoadFromWebAsync(url, Encoding.UTF8, new NetworkCredential(), cts.Token);
+ var innerHtml = doc.DocumentNode.InnerHtml;
+
+ return innerHtml;
+ }
+
+ ///
+ /// Converts HTML content to the Markdown format.
+ ///
+ /// The HTML content to parse.
+ /// The converted Markdown content.
+ public string ParseToMarkdown(string html)
+ {
+ var markdownConverter = new Converter(MARKDOWN_PARSER_CONFIG);
+ return markdownConverter.Convert(html);
+ }
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Tools/Process.cs b/app/MindWork AI Studio/Tools/Process.cs
new file mode 100644
index 0000000..5348891
--- /dev/null
+++ b/app/MindWork AI Studio/Tools/Process.cs
@@ -0,0 +1,67 @@
+using System.Text;
+
+namespace AIStudio.Tools;
+
+public sealed class Process where T : struct, Enum
+{
+ public static readonly Process INSTANCE = new();
+
+ private readonly Dictionary stepsData = [];
+ private readonly int min = int.MaxValue;
+ private readonly int max = int.MinValue;
+ private readonly string[] labels;
+
+ private Process()
+ {
+ var values = Enum.GetValues();
+ this.labels = new string[values.Length];
+
+ for (var i = 0; i < values.Length; i++)
+ {
+ var value = values[i];
+ var stepValue = Convert.ToInt32(value);
+ var stepName = DeriveName(value);
+
+ this.labels[i] = stepName;
+ this.stepsData[value] = new ProcessStepValue(stepValue, stepName);
+
+ if (stepValue < this.min)
+ this.min = stepValue;
+
+ if (stepValue > this.max)
+ this.max = stepValue;
+ }
+ }
+
+ private static string DeriveName(T value)
+ {
+ var text = value.ToString();
+ if (!text.Contains('_'))
+ {
+ text = text.ToLowerInvariant();
+ text = char.ToUpperInvariant(text[0]) + text[1..];
+ }
+ else
+ {
+ var parts = text.Split('_');
+ var sb = new StringBuilder();
+ foreach (var part in parts)
+ {
+ sb.Append(char.ToUpperInvariant(part[0]));
+ sb.Append(part[1..].ToLowerInvariant());
+ }
+
+ text = sb.ToString();
+ }
+
+ return text;
+ }
+
+ public string[] Labels => this.labels;
+
+ public int Min => this.min;
+
+ public int Max => this.max;
+
+ public ProcessStepValue this[T step] => this.stepsData[step];
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Tools/ProcessStepValue.cs b/app/MindWork AI Studio/Tools/ProcessStepValue.cs
new file mode 100644
index 0000000..b75b5e0
--- /dev/null
+++ b/app/MindWork AI Studio/Tools/ProcessStepValue.cs
@@ -0,0 +1,258 @@
+using System.Globalization;
+using System.Numerics;
+
+namespace AIStudio.Tools;
+
+public readonly record struct ProcessStepValue(int Step, string Name) : INumber
+{
+ public static implicit operator int(ProcessStepValue process) => process.Step;
+
+ #region INumber implementation
+
+ #region Implementation of IComparable
+
+ public int CompareTo(object? obj) => this.Step.CompareTo(obj);
+
+ #endregion
+
+ #region Implementation of IComparable
+
+ public int CompareTo(ProcessStepValue other) => this.Step.CompareTo(other.Step);
+
+ #endregion
+
+ #region Implementation of IFormattable
+
+ public string ToString(string? format, IFormatProvider? formatProvider) => this.Step.ToString(format, formatProvider);
+
+ #endregion
+
+ #region Implementation of IParsable
+
+ public static ProcessStepValue Parse(string s, IFormatProvider? provider) => new(int.Parse(s, provider), string.Empty);
+
+ public static bool TryParse(string? s, IFormatProvider? provider, out ProcessStepValue result)
+ {
+ if (int.TryParse(s, provider, out var stepValue))
+ {
+ result = new ProcessStepValue(stepValue, string.Empty);
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+ #endregion
+
+ #region Implementation of ISpanFormattable
+
+ public bool TryFormat(Span destination, out int charsWritten, ReadOnlySpan format, IFormatProvider? provider) => this.Step.TryFormat(destination, out charsWritten, format, provider);
+
+ #endregion
+
+ #region Implementation of ISpanParsable
+
+ public static ProcessStepValue Parse(ReadOnlySpan s, IFormatProvider? provider) => new(int.Parse(s, provider), string.Empty);
+
+ public static bool TryParse(ReadOnlySpan s, IFormatProvider? provider, out ProcessStepValue result)
+ {
+ if (int.TryParse(s, provider, out int stepValue))
+ {
+ result = new ProcessStepValue(stepValue, string.Empty);
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+
+ #endregion
+
+ #region Implementation of IAdditionOperators
+
+ public static ProcessStepValue operator +(ProcessStepValue left, ProcessStepValue right) => left with { Step = left.Step + right.Step };
+
+ #endregion
+
+ #region Implementation of IAdditiveIdentity
+
+ public static ProcessStepValue AdditiveIdentity => new(0, string.Empty);
+
+ #endregion
+
+ #region Implementation of IComparisonOperators
+
+ public static bool operator >(ProcessStepValue left, ProcessStepValue right) => left.Step > right.Step;
+
+ public static bool operator >=(ProcessStepValue left, ProcessStepValue right) => left.Step >= right.Step;
+
+ public static bool operator <(ProcessStepValue left, ProcessStepValue right) => left.Step < right.Step;
+
+ public static bool operator <=(ProcessStepValue left, ProcessStepValue right) => left.Step <= right.Step;
+
+ #endregion
+
+ #region Implementation of IDecrementOperators
+
+ public static ProcessStepValue operator --(ProcessStepValue value) => value with { Step = value.Step - 1 };
+
+ #endregion
+
+ #region Implementation of IDivisionOperators
+
+ public static ProcessStepValue operator /(ProcessStepValue left, ProcessStepValue right) => left with { Step = left.Step / right.Step };
+
+ #endregion
+
+ #region Implementation of IIncrementOperators
+
+ public static ProcessStepValue operator ++(ProcessStepValue value) => value with { Step = value.Step + 1 };
+
+ #endregion
+
+ #region Implementation of IModulusOperators
+
+ public static ProcessStepValue operator %(ProcessStepValue left, ProcessStepValue right) => left with { Step = left.Step % right.Step };
+
+ #endregion
+
+ #region Implementation of IMultiplicativeIdentity
+
+ public static ProcessStepValue MultiplicativeIdentity => new(1, string.Empty);
+
+ #endregion
+
+ #region Implementation of IMultiplyOperators
+
+ public static ProcessStepValue operator *(ProcessStepValue left, ProcessStepValue right) => left with { Step = left.Step * right.Step };
+
+ #endregion
+
+ #region Implementation of ISubtractionOperators
+
+ public static ProcessStepValue operator -(ProcessStepValue left, ProcessStepValue right) => left with { Step = left.Step - right.Step };
+
+ #endregion
+
+ #region Implementation of IUnaryNegationOperators
+
+ public static ProcessStepValue operator -(ProcessStepValue value) => value with { Step = -value.Step };
+
+ #endregion
+
+ #region Implementation of IUnaryPlusOperators
+
+ public static ProcessStepValue operator +(ProcessStepValue value) => value;
+
+ #endregion
+
+ #region Implementation of INumberBase
+
+ public static ProcessStepValue Abs(ProcessStepValue value) => value with { Step = Math.Abs(value.Step) };
+
+ public static bool IsCanonical(ProcessStepValue value) => true;
+ public static bool IsComplexNumber(ProcessStepValue value) => false;
+ public static bool IsEvenInteger(ProcessStepValue value) => value.Step % 2 == 0;
+ public static bool IsFinite(ProcessStepValue value) => true;
+ public static bool IsImaginaryNumber(ProcessStepValue value) => false;
+ public static bool IsInfinity(ProcessStepValue value) => false;
+ public static bool IsInteger(ProcessStepValue value) => true;
+ public static bool IsNaN(ProcessStepValue value) => false;
+ public static bool IsNegative(ProcessStepValue value) => value.Step < 0;
+ public static bool IsNegativeInfinity(ProcessStepValue value) => false;
+ public static bool IsNormal(ProcessStepValue value) => true;
+ public static bool IsOddInteger(ProcessStepValue value) => value.Step % 2 != 0;
+ public static bool IsPositive(ProcessStepValue value) => value.Step > 0;
+ public static bool IsPositiveInfinity(ProcessStepValue value) => false;
+ public static bool IsRealNumber(ProcessStepValue value) => true;
+ public static bool IsSubnormal(ProcessStepValue value) => false;
+ public static bool IsZero(ProcessStepValue value) => value.Step == 0;
+ public static ProcessStepValue MaxMagnitude(ProcessStepValue x, ProcessStepValue y)
+ {
+ return x with { Step = Math.Max(Math.Abs(x.Step), Math.Abs(y.Step)) };
+ }
+
+ public static ProcessStepValue MaxMagnitudeNumber(ProcessStepValue x, ProcessStepValue y) => MaxMagnitude(x, y);
+
+ public static ProcessStepValue MinMagnitude(ProcessStepValue x, ProcessStepValue y) => x with { Step = Math.Min(Math.Abs(x.Step), Math.Abs(y.Step)) };
+
+ public static ProcessStepValue MinMagnitudeNumber(ProcessStepValue x, ProcessStepValue y) => MinMagnitude(x, y);
+
+ public static ProcessStepValue Parse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider) => new(int.Parse(s, style, provider), string.Empty);
+
+ public static ProcessStepValue Parse(string s, NumberStyles style, IFormatProvider? provider) => new(int.Parse(s, style, provider), string.Empty);
+
+ public static bool TryConvertFromChecked(TOther value, out ProcessStepValue result) where TOther : INumberBase
+ {
+ if (TOther.TryConvertToChecked(value, out int intValue))
+ {
+ result = new ProcessStepValue(intValue, string.Empty);
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+
+ public static bool TryConvertFromSaturating(TOther value, out ProcessStepValue result) where TOther : INumberBase
+ {
+ if (TOther.TryConvertToSaturating(value, out int intValue))
+ {
+ result = new ProcessStepValue(intValue, string.Empty);
+ return true;
+ }
+ result = default;
+ return false;
+ }
+
+ public static bool TryConvertFromTruncating(TOther value, out ProcessStepValue result) where TOther : INumberBase
+ {
+ if (TOther.TryConvertToTruncating(value, out int intValue))
+ {
+ result = new ProcessStepValue(intValue, string.Empty);
+ return true;
+ }
+ result = default;
+ return false;
+ }
+
+ public static bool TryConvertToChecked(ProcessStepValue value, out TOther result) where TOther : INumberBase => TOther.TryConvertFromChecked(value.Step, out result!);
+
+ public static bool TryConvertToSaturating(ProcessStepValue value, out TOther result) where TOther : INumberBase => TOther.TryConvertFromSaturating(value.Step, out result!);
+
+ public static bool TryConvertToTruncating(ProcessStepValue value, out TOther result) where TOther : INumberBase => TOther.TryConvertFromTruncating(value.Step, out result!);
+
+ public static bool TryParse(ReadOnlySpan s, NumberStyles style, IFormatProvider? provider, out ProcessStepValue result)
+ {
+ if (int.TryParse(s, style, provider, out var stepValue))
+ {
+ result = new ProcessStepValue(stepValue, string.Empty);
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+
+ public static bool TryParse(string? s, NumberStyles style, IFormatProvider? provider, out ProcessStepValue result)
+ {
+ if (int.TryParse(s, style, provider, out var stepValue))
+ {
+ result = new ProcessStepValue(stepValue, string.Empty);
+ return true;
+ }
+
+ result = default;
+ return false;
+ }
+
+ public static ProcessStepValue One => new(1, string.Empty);
+
+ public static int Radix => 2;
+
+ public static ProcessStepValue Zero => new(0, string.Empty);
+
+ #endregion
+
+ #endregion
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/Tools/ThreadSafeRandom.cs b/app/MindWork AI Studio/Tools/ThreadSafeRandom.cs
new file mode 100644
index 0000000..27bb61a
--- /dev/null
+++ b/app/MindWork AI Studio/Tools/ThreadSafeRandom.cs
@@ -0,0 +1,88 @@
+namespace AIStudio.Tools;
+
+///
+public sealed class ThreadSafeRandom : Random
+{
+ private static readonly object LOCK = new();
+
+ #region Overrides of Random
+
+ ///
+ public override int Next()
+ {
+ lock (LOCK)
+ return base.Next();
+ }
+
+ ///
+ public override int Next(int maxValue)
+ {
+ lock (LOCK)
+ return base.Next(maxValue);
+ }
+
+ ///
+ public override int Next(int minValue, int maxValue)
+ {
+ lock (LOCK)
+ return base.Next(minValue, maxValue);
+ }
+
+ ///
+ public override void NextBytes(byte[] buffer)
+ {
+ lock (LOCK)
+ base.NextBytes(buffer);
+ }
+
+ ///
+ public override void NextBytes(Span buffer)
+ {
+ lock (LOCK)
+ base.NextBytes(buffer);
+ }
+
+ ///
+ public override double NextDouble()
+ {
+ lock (LOCK)
+ return base.NextDouble();
+ }
+
+ ///
+ public override long NextInt64()
+ {
+ lock (LOCK)
+ return base.NextInt64();
+ }
+
+ ///
+ public override long NextInt64(long maxValue)
+ {
+ lock (LOCK)
+ return base.NextInt64(maxValue);
+ }
+
+ ///
+ public override long NextInt64(long minValue, long maxValue)
+ {
+ lock (LOCK)
+ return base.NextInt64(minValue, maxValue);
+ }
+
+ ///
+ public override float NextSingle()
+ {
+ lock (LOCK)
+ return base.NextSingle();
+ }
+
+ ///
+ protected override double Sample()
+ {
+ lock (LOCK)
+ return base.Sample();
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/packages.lock.json b/app/MindWork AI Studio/packages.lock.json
index 5dd25e9..220be60 100644
--- a/app/MindWork AI Studio/packages.lock.json
+++ b/app/MindWork AI Studio/packages.lock.json
@@ -2,6 +2,12 @@
"version": 1,
"dependencies": {
"net8.0": {
+ "HtmlAgilityPack": {
+ "type": "Direct",
+ "requested": "[1.11.62, )",
+ "resolved": "1.11.62",
+ "contentHash": "KS4h7ZjWsO6YixRfQgYdR+PZMbTaZod1LBPi+1Ph7dJCARzQm7DOKe5HPhP/o0EWX5l7QCgAZHa4VOa4pQa8JQ=="
+ },
"Microsoft.Extensions.FileProviders.Embedded": {
"type": "Direct",
"requested": "[8.0.7, )",
@@ -38,6 +44,15 @@
"MudBlazor": "6.20.0"
}
},
+ "ReverseMarkdown": {
+ "type": "Direct",
+ "requested": "[4.6.0, )",
+ "resolved": "4.6.0",
+ "contentHash": "ehNpMz3yQwd7P/vHpwi4KyDlT8UtVmtiL+NTb6mFEPzbLqJXbRIGF4OxEA5tuBA5Cfwhzf537TX1UIB6dUpo7A==",
+ "dependencies": {
+ "HtmlAgilityPack": "1.11.61"
+ }
+ },
"Markdig": {
"type": "Transitive",
"resolved": "0.37.0",
@@ -163,6 +178,6 @@
"contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA=="
}
},
- "net8.0/osx-x64": {}
+ "net8.0/osx-arm64": {}
}
}
\ No newline at end of file
diff --git a/app/MindWork AI Studio/wwwroot/changelog/v0.8.6.md b/app/MindWork AI Studio/wwwroot/changelog/v0.8.6.md
index 00280c0..2025227 100644
--- a/app/MindWork AI Studio/wwwroot/changelog/v0.8.6.md
+++ b/app/MindWork AI Studio/wwwroot/changelog/v0.8.6.md
@@ -1,5 +1,9 @@
-# v0.8.6, build 168
+# v0.8.6, build 168 (2024-08-01 19:50 UTC)
- Added possibility to configure a default provider for chats
+- Added architecture for future agent usage
+- Added a first agent to read, analyze and extract text from Markdown data
+- Added option to read web content into translation and text summarization assistants
- Improved the readability of the `settings.json` file by using indentation and enum names instead of numbers
- Improved assistant overview; assistants will now wrap to the next line if there are too many to fit on the row
-- Increased the default value for the live translation delay from 1,000 to 1,500 ms
\ No newline at end of file
+- Increased the default value for the live translation delay from 1,000 to 3_000 ms
+- Fixed random number generator usage to be thread-safe
\ No newline at end of file
diff --git a/metadata.txt b/metadata.txt
index 0d4231b..51f9c8e 100644
--- a/metadata.txt
+++ b/metadata.txt
@@ -1,9 +1,9 @@
-0.8.5
-2024-07-28 16:44:01 UTC
-167
+0.8.6
+2024-08-01 19:50:02 UTC
+168
8.0.107 (commit 1bdaef7265)
8.0.7 (commit 2aade6beb0)
1.80.0 (commit 051478957)
7.4.0
1.7.1
-c1b92a05fc7, release
+199be1e863f, release
diff --git a/runtime/Cargo.lock b/runtime/Cargo.lock
index fdbe55d..a7bc970 100644
--- a/runtime/Cargo.lock
+++ b/runtime/Cargo.lock
@@ -2308,7 +2308,7 @@ checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mindwork-ai-studio"
-version = "0.8.5"
+version = "0.8.6"
dependencies = [
"arboard",
"flexi_logger",
diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml
index feda293..8f64fca 100644
--- a/runtime/Cargo.toml
+++ b/runtime/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "mindwork-ai-studio"
-version = "0.8.5"
+version = "0.8.6"
edition = "2021"
description = "MindWork AI Studio"
authors = ["Thorsten Sommer"]
diff --git a/runtime/tauri.conf.json b/runtime/tauri.conf.json
index 1799966..315a8a3 100644
--- a/runtime/tauri.conf.json
+++ b/runtime/tauri.conf.json
@@ -6,7 +6,7 @@
},
"package": {
"productName": "MindWork AI Studio",
- "version": "0.8.5"
+ "version": "0.8.6"
},
"tauri": {
"allowlist": {