From 8a735c2bbe44990d3745a25b293a872c8813467e Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sun, 13 Sep 2026 16:24:36 +0200 Subject: [PATCH] Fixed the web content URL not being reset in the assistants (#964) --- .../Assistants/Dynamic/AssistantDynamic.razor | 1 + .../Assistants/Dynamic/WebContentState.cs | 3 +- .../LegalCheck/AssistantLegalCheck.razor | 2 +- .../LegalCheck/AssistantLegalCheck.razor.cs | 5 ++ .../AssistantTextSummarizer.razor | 2 +- .../AssistantTextSummarizer.razor.cs | 5 ++ .../Translation/AssistantTranslation.razor | 2 +- .../Translation/AssistantTranslation.razor.cs | 5 ++ .../Components/ReadWebContent.razor | 4 +- .../Components/ReadWebContent.razor.cs | 58 ++++++++++++------- .../wwwroot/changelog/v26.9.1.md | 2 + 11 files changed, 62 insertions(+), 27 deletions(-) diff --git a/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor b/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor index 99a87f3e..3fef72c8 100644 --- a/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor +++ b/app/MindWork AI Studio/Assistants/Dynamic/AssistantDynamic.razor @@ -140,6 +140,7 @@ else var webState = this.assistantState.WebContent[webContent.Name];
+ } @* Two zones, so no default target: the user has to aim at the one they mean. *@ diff --git a/app/MindWork AI Studio/Assistants/LegalCheck/AssistantLegalCheck.razor.cs b/app/MindWork AI Studio/Assistants/LegalCheck/AssistantLegalCheck.razor.cs index 68be4a20..61cae193 100644 --- a/app/MindWork AI Studio/Assistants/LegalCheck/AssistantLegalCheck.razor.cs +++ b/app/MindWork AI Studio/Assistants/LegalCheck/AssistantLegalCheck.razor.cs @@ -36,6 +36,7 @@ public partial class AssistantLegalCheck : AssistantBaseCore SHOW_WEB_CONTENT_READER_STATE_KEY = new(nameof(showWebContentReader)); private static readonly AssistantSessionStateKey USE_CONTENT_CLEANER_AGENT_STATE_KEY = new(nameof(useContentCleanerAgent)); private static readonly AssistantSessionStateKey IS_AGENT_RUNNING_STATE_KEY = new(nameof(isAgentRunning)); + private static readonly AssistantSessionStateKey WEB_CONTENT_URL_STATE_KEY = new(nameof(webContentURL)); private static readonly AssistantSessionStateKey INPUT_LEGAL_DOCUMENT_STATE_KEY = new(nameof(inputLegalDocument)); private static readonly AssistantSessionStateKey INPUT_QUESTIONS_STATE_KEY = new(nameof(inputQuestions)); @@ -72,6 +75,7 @@ public partial class AssistantLegalCheck : AssistantBaseCore this.showWebContentReader = value); state.Restore(USE_CONTENT_CLEANER_AGENT_STATE_KEY, value => this.useContentCleanerAgent = value); state.Restore(IS_AGENT_RUNNING_STATE_KEY, value => this.isAgentRunning = value); + state.Restore(WEB_CONTENT_URL_STATE_KEY, value => this.webContentURL = value); state.Restore(INPUT_LEGAL_DOCUMENT_STATE_KEY, value => this.inputLegalDocument = value); state.Restore(INPUT_QUESTIONS_STATE_KEY, value => this.inputQuestions = value); } diff --git a/app/MindWork AI Studio/Assistants/TextSummarizer/AssistantTextSummarizer.razor b/app/MindWork AI Studio/Assistants/TextSummarizer/AssistantTextSummarizer.razor index 862bb856..2992e448 100644 --- a/app/MindWork AI Studio/Assistants/TextSummarizer/AssistantTextSummarizer.razor +++ b/app/MindWork AI Studio/Assistants/TextSummarizer/AssistantTextSummarizer.razor @@ -3,7 +3,7 @@ @if (!this.SettingsManager.ConfigurationData.TextSummarizer.HideWebContentReader) { - + } diff --git a/app/MindWork AI Studio/Assistants/TextSummarizer/AssistantTextSummarizer.razor.cs b/app/MindWork AI Studio/Assistants/TextSummarizer/AssistantTextSummarizer.razor.cs index 64fbcc5a..142e574b 100644 --- a/app/MindWork AI Studio/Assistants/TextSummarizer/AssistantTextSummarizer.razor.cs +++ b/app/MindWork AI Studio/Assistants/TextSummarizer/AssistantTextSummarizer.razor.cs @@ -35,6 +35,7 @@ public partial class AssistantTextSummarizer : AssistantBaseCore SHOW_WEB_CONTENT_READER_STATE_KEY = new(nameof(showWebContentReader)); private static readonly AssistantSessionStateKey USE_CONTENT_CLEANER_AGENT_STATE_KEY = new(nameof(useContentCleanerAgent)); + private static readonly AssistantSessionStateKey WEB_CONTENT_URL_STATE_KEY = new(nameof(webContentURL)); private static readonly AssistantSessionStateKey INPUT_TEXT_STATE_KEY = new(nameof(inputText)); private static readonly AssistantSessionStateKey IS_AGENT_RUNNING_STATE_KEY = new(nameof(isAgentRunning)); private static readonly AssistantSessionStateKey SELECTED_TARGET_LANGUAGE_STATE_KEY = new(nameof(selectedTargetLanguage)); @@ -88,6 +91,7 @@ public partial class AssistantTextSummarizer : AssistantBaseCore this.showWebContentReader = value); state.Restore(USE_CONTENT_CLEANER_AGENT_STATE_KEY, value => this.useContentCleanerAgent = value); + state.Restore(WEB_CONTENT_URL_STATE_KEY, value => this.webContentURL = value); state.Restore(INPUT_TEXT_STATE_KEY, value => this.inputText = value); state.Restore(IS_AGENT_RUNNING_STATE_KEY, value => this.isAgentRunning = value); state.Restore(SELECTED_TARGET_LANGUAGE_STATE_KEY, value => this.selectedTargetLanguage = value); diff --git a/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor b/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor index 525aa2ff..fab6b4ee 100644 --- a/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor +++ b/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor @@ -3,7 +3,7 @@ @if (!this.SettingsManager.ConfigurationData.Translation.HideWebContentReader) { - + } diff --git a/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor.cs b/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor.cs index 87f445c7..984715a8 100644 --- a/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor.cs +++ b/app/MindWork AI Studio/Assistants/Translation/AssistantTranslation.razor.cs @@ -47,6 +47,7 @@ public partial class AssistantTranslation : AssistantBaseCore USE_CONTENT_CLEANER_AGENT_STATE_KEY = new(nameof(useContentCleanerAgent)); private static readonly AssistantSessionStateKey LIVE_TRANSLATION_STATE_KEY = new(nameof(liveTranslation)); private static readonly AssistantSessionStateKey IS_AGENT_RUNNING_STATE_KEY = new(nameof(isAgentRunning)); + private static readonly AssistantSessionStateKey WEB_CONTENT_URL_STATE_KEY = new(nameof(webContentURL)); private static readonly AssistantSessionStateKey INPUT_TEXT_STATE_KEY = new(nameof(inputText)); private static readonly AssistantSessionStateKey INPUT_TEXT_LAST_TRANSLATION_STATE_KEY = new(nameof(inputTextLastTranslation)); private static readonly AssistantSessionStateKey SELECTED_TARGET_LANGUAGE_STATE_KEY = new(nameof(selectedTargetLanguage)); @@ -96,6 +99,7 @@ public partial class AssistantTranslation : AssistantBaseCore this.useContentCleanerAgent = value); state.Restore(LIVE_TRANSLATION_STATE_KEY, value => this.liveTranslation = value); state.Restore(IS_AGENT_RUNNING_STATE_KEY, value => this.isAgentRunning = value); + state.Restore(WEB_CONTENT_URL_STATE_KEY, value => this.webContentURL = value); state.Restore(INPUT_TEXT_STATE_KEY, value => this.inputText = value); state.Restore(INPUT_TEXT_LAST_TRANSLATION_STATE_KEY, value => this.inputTextLastTranslation = value); state.Restore(SELECTED_TARGET_LANGUAGE_STATE_KEY, value => this.selectedTargetLanguage = value); diff --git a/app/MindWork AI Studio/Components/ReadWebContent.razor b/app/MindWork AI Studio/Components/ReadWebContent.razor index 2a6aadb1..10ebc52d 100644 --- a/app/MindWork AI Studio/Components/ReadWebContent.razor +++ b/app/MindWork AI Studio/Components/ReadWebContent.razor @@ -5,8 +5,8 @@ { - diff --git a/app/MindWork AI Studio/Components/ReadWebContent.razor.cs b/app/MindWork AI Studio/Components/ReadWebContent.razor.cs index 550a8bde..22721a1d 100644 --- a/app/MindWork AI Studio/Components/ReadWebContent.razor.cs +++ b/app/MindWork AI Studio/Components/ReadWebContent.razor.cs @@ -35,7 +35,20 @@ public partial class ReadWebContent : MSGComponentBase [Parameter] public EventCallback ContentChanged { get; set; } - + + /// + /// The URL the content is loaded from. + /// + /// + /// The URL belongs to the parent, so that it is cleared when the parent resets its form and + /// is kept when the parent stores its state. + /// + [Parameter] + public string URL { get; set; } = string.Empty; + + [Parameter] + public EventCallback URLChanged { get; set; } + [Parameter] public AIStudio.Settings.Provider ProviderSettings { get; set; } = AIStudio.Settings.Provider.NONE; @@ -60,8 +73,6 @@ public partial class ReadWebContent : MSGComponentBase private readonly Process process = Process.INSTANCE; private ProcessStepValue processStep; - private string providedURL = string.Empty; - private bool urlIsValid; private bool isProviderValid; private AIStudio.Settings.Provider providerSettings = AIStudio.Settings.Provider.NONE; @@ -105,7 +116,7 @@ public partial class ReadWebContent : MSGComponentBase // the URL, so their own network is not off limits. // var retrievedPage = await this.WebPageRetrievalService.RetrieveAsync( - new Uri(this.providedURL), + new Uri(this.URL), new WebPageRetrievalOptions { TimeoutSeconds = TIMEOUT_SECONDS, @@ -115,14 +126,14 @@ public partial class ReadWebContent : MSGComponentBase this.processStep = this.process[ReadWebContentSteps.PARSING]; this.StateHasChanged(); markdown = retrievedPage.ExtractedPage.Markdown; - markdown = await this.PromptInjectionGuardService.SanitizeAsync(markdown, PromptInjectionSource.WebContent(this.providedURL)); + markdown = await this.PromptInjectionGuardService.SanitizeAsync(markdown, PromptInjectionSource.WebContent(this.URL)); if (this.PreselectContentCleanerAgent && this.providerSettings != AIStudio.Settings.Provider.NONE) { this.AgentTextContentCleaner.ProviderSettings = this.providerSettings; var additionalData = new Dictionary { - { "sourceURL", this.providedURL }, + { "sourceURL", this.URL }, }; this.processStep = this.process[ReadWebContentSteps.CLEANING]; @@ -164,8 +175,8 @@ public partial class ReadWebContent : MSGComponentBase // and the reasons a page cannot be read are things the user can act on: a link to a // PDF rather than a page, a host that does not answer, a server refusing the request. // - this.Logger.LogWarning(exception, "Could not load the web content from '{ProvidedUrl}'.", this.providedURL); - await this.MessageBus.SendError(new(Icons.Material.Filled.CloudOff, string.Format(this.T("The content of '{0}' could not be loaded: {1}"), this.providedURL, exception.Message))); + this.Logger.LogWarning(exception, "Could not load the web content from '{ProvidedUrl}'.", this.URL); + await this.MessageBus.SendError(new(Icons.Material.Filled.CloudOff, string.Format(this.T("The content of '{0}' could not be loaded: {1}"), this.URL, exception.Message))); } this.Content = markdown; @@ -176,16 +187,31 @@ public partial class ReadWebContent : MSGComponentBase { get { - if(!this.urlIsValid) + if(!this.UrlIsValid) return false; - + if(this.PreselectContentCleanerAgent && !this.isProviderValid) return false; - + return true; } } + /// + /// Whether the current URL can be loaded. + /// + /// + /// Asked of the current value instead of remembered from the last validation run: the parent + /// clears the URL when it resets its form, and the form validation does not run again at that + /// point. The fetch button would otherwise stay enabled with an empty field. + /// + private bool UrlIsValid => this.ValidateURL(this.URL) is null; + + private async Task URLValueChanged(string url) + { + await this.URLChanged.InvokeAsync(url); + } + private async Task ShowWebContentReaderChanged(bool state) { await this.PreselectChanged.InvokeAsync(state); @@ -211,25 +237,15 @@ public partial class ReadWebContent : MSGComponentBase private string? ValidateURL(string url) { if(string.IsNullOrWhiteSpace(url)) - { - this.urlIsValid = false; return T("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 T("Please provide a valid URL."); - } if(uriResult is not { Scheme: "http" or "https" }) - { - this.urlIsValid = false; return T("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/wwwroot/changelog/v26.9.1.md b/app/MindWork AI Studio/wwwroot/changelog/v26.9.1.md index 21c78ebb..b3fa66b5 100644 --- a/app/MindWork AI Studio/wwwroot/changelog/v26.9.1.md +++ b/app/MindWork AI Studio/wwwroot/changelog/v26.9.1.md @@ -29,5 +29,7 @@ - Fixed a model resold under a plain name not getting the abilities it really has. - Fixed image and video generation models showing up among the chat models. - Fixed a dropped file being processed several times, e.g., after the computer woke up from sleep. +- Fixed the web address staying in the field when you reset an assistant that loads content from a web page. +- Fixed the web address being gone when you leave such an assistant and come back to it later. - Fixed the Visual Briefing Assistant (in preview) not scrolling, which put everything below the window edge out of reach and made the assistant unusable. The briefing preview is now shown at its intended size inside its frame, and switching between the desktop, tablet, and mobile view changes its width as it should. - Upgraded the Visual Briefing Assistant (in preview) from the prototype to the beta state. The assistant is now completely implemented and is undergoing a deeper testing phase in preparation for release. To try it, open the app settings, allow preview features down to beta, and then enable the Visual Briefing Assistant there.