diff --git a/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs b/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs index d309c825..ae0cfdbe 100644 --- a/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs +++ b/app/MindWork AI Studio/Assistants/AssistantBase.razor.cs @@ -142,6 +142,7 @@ public abstract partial class AssistantBase : AssistantLowerBase wher private bool isDisposed; private AssistantSessionKey assistantSessionKey; private Guid? assistantSessionId; + private AssistantSessionSnapshot? pendingRenderedAssistantSessionSnapshot; /// /// Gets whether the Blazor component instance has already been disposed. @@ -195,6 +196,12 @@ public abstract partial class AssistantBase : AssistantLowerBase wher // We don't want to show validation errors when the user opens the dialog. if(firstRender) this.Form?.ResetValidation(); + + if (this.pendingRenderedAssistantSessionSnapshot is { } snapshot) + { + this.pendingRenderedAssistantSessionSnapshot = null; + await this.OnAssistantSessionRenderedAsync(snapshot); + } await base.OnAfterRenderAsync(firstRender); } @@ -229,7 +236,7 @@ public abstract partial class AssistantBase : AssistantLowerBase wher this.CancellationTokenSource = new(); this.isProcessing = true; - var startedSession = this.AssistantSessionService.TryBegin(this.assistantSessionKey, this.Title, this.CancellationTokenSource, this.ChatThread, this.CaptureAssistantSessionState()); + var startedSession = await this.AssistantSessionService.TryBeginAsync(this.assistantSessionKey, this.Title, this.CancellationTokenSource, this.ChatThread, this.CaptureAssistantSessionState()); if (startedSession.IsActive is not true || startedSession.Key != this.assistantSessionKey) { this.CancellationTokenSource.Dispose(); @@ -658,6 +665,13 @@ public abstract partial class AssistantBase : AssistantLowerBase wher /// A task that completes after derived UI restore work has finished. protected virtual Task OnAssistantSessionAttachedAsync(AssistantSessionSnapshot snapshot) => Task.CompletedTask; + /// + /// Allows derived assistants to restore DOM-dependent client-only UI after an attached session was rendered. + /// + /// The assistant session snapshot that was rendered. + /// A task that completes after derived UI restore work has finished. + protected virtual Task OnAssistantSessionRenderedAsync(AssistantSessionSnapshot snapshot) => Task.CompletedTask; + /// /// Handles assistant session change events for the current assistant instance. /// @@ -710,6 +724,9 @@ public abstract partial class AssistantBase : AssistantLowerBase wher if (restoreClientOnlyContent) await this.OnAssistantSessionAttachedAsync(snapshot); + if (restoreClientOnlyContent) + this.pendingRenderedAssistantSessionSnapshot = snapshot; + await this.RefreshAssistantUIAsync(); } diff --git a/app/MindWork AI Studio/Assistants/GrammarSpelling/AssistantGrammarSpelling.razor.cs b/app/MindWork AI Studio/Assistants/GrammarSpelling/AssistantGrammarSpelling.razor.cs index 6ba1e0eb..ea6b1077 100644 --- a/app/MindWork AI Studio/Assistants/GrammarSpelling/AssistantGrammarSpelling.razor.cs +++ b/app/MindWork AI Studio/Assistants/GrammarSpelling/AssistantGrammarSpelling.razor.cs @@ -154,7 +154,7 @@ public partial class AssistantGrammarSpelling : AssistantBaseCoreThe current assistant chat thread, if one already exists. /// The initial assistant component state. /// The new session snapshot, or the existing active session snapshot. - public AssistantSessionSnapshot TryBegin(AssistantSessionKey key, string title, CancellationTokenSource cancellationTokenSource, ChatThread? chatThread, Dictionary state) + public async Task TryBeginAsync(AssistantSessionKey key, string title, CancellationTokenSource cancellationTokenSource, ChatThread? chatThread, Dictionary state) { if (this.sessions.TryGetValue(key, out var existing) && existing.Status is AssistantSessionStatus.RUNNING or AssistantSessionStatus.CANCELING) return CreateSnapshot(existing); @@ -142,8 +142,9 @@ public sealed class AssistantSessionService(MessageBus messageBus) }; this.sessions[key] = session; - _ = this.NotifyChangedAsync(session); - return CreateSnapshot(session); + var snapshot = CreateSnapshot(session); + await this.NotifyChangedAsync(session); + return snapshot; } /// diff --git a/app/MindWork AI Studio/wwwroot/app.js b/app/MindWork AI Studio/wwwroot/app.js index c2845f76..0f2a49ec 100644 --- a/app/MindWork AI Studio/wwwroot/app.js +++ b/app/MindWork AI Studio/wwwroot/app.js @@ -1,10 +1,18 @@ window.generateDiff = function (text1, text2, divDiff, divLegend) { let wikEdDiff = new WikEdDiff(); let targetDiv = document.getElementById(divDiff) + if (!targetDiv) { + return; + } + targetDiv.innerHTML = wikEdDiff.diff(text1, text2); targetDiv.classList.add('mud-typography-body1', 'improvedDiff'); let legend = document.getElementById(divLegend); + if (!legend) { + return; + } + legend.innerHTML = `

Legend

@@ -20,6 +28,10 @@ window.generateDiff = function (text1, text2, divDiff, divLegend) { window.clearDiv = function (divName) { let targetDiv = document.getElementById(divName); + if (!targetDiv) { + return; + } + targetDiv.innerHTML = ''; }