Enhance assistant session methods to include sending component reference

This commit is contained in:
Thorsten Sommer 2026-07-03 14:01:53 +02:00
parent 791f20df15
commit beabc8ef02
Signed by untrusted user who does not match committer: tsommer
GPG Key ID: 371BBA77A02C0108
2 changed files with 29 additions and 15 deletions

View File

@ -221,7 +221,7 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
this.CancellationTokenSource = new(); this.CancellationTokenSource = new();
this.IsProcessing = true; this.IsProcessing = true;
var startedSession = await this.AssistantSessionService.TryBeginAsync(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(), this);
if (startedSession.IsActive is not true || startedSession.Key != this.assistantSessionKey) if (startedSession.IsActive is not true || startedSession.Key != this.assistantSessionKey)
{ {
this.CancellationTokenSource.Dispose(); this.CancellationTokenSource.Dispose();
@ -265,7 +265,11 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
var sessionCancellationTokenSource = this.CancellationTokenSource; var sessionCancellationTokenSource = this.CancellationTokenSource;
this.CancellationTokenSource = null; this.CancellationTokenSource = null;
if (this.assistantSessionId is { } sessionId) if (this.assistantSessionId is { } sessionId)
await this.AssistantSessionService.CompleteAsync(this.assistantSessionKey, sessionId, sessionStatus, errorMessage, this.ChatThread, this.CaptureAssistantSessionState()); {
await this.AssistantSessionService.CompleteAsync(this.assistantSessionKey, sessionId, sessionStatus, errorMessage, this.ChatThread, this.CaptureAssistantSessionState(), this);
if (!this.isDisposed)
_ = this.AssistantSessionService.TryTakeInactiveSnapshot(this.assistantSessionKey);
}
sessionCancellationTokenSource?.Dispose(); sessionCancellationTokenSource?.Dispose();
await this.RefreshAssistantUIAsync(); await this.RefreshAssistantUIAsync();
} }
@ -452,7 +456,7 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
private async Task CancelStreaming() private async Task CancelStreaming()
{ {
await this.AssistantSessionService.CancelAsync(this.assistantSessionKey); await this.AssistantSessionService.CancelAsync(this.assistantSessionKey, this);
} }
protected async Task CopyToClipboard() protected async Task CopyToClipboard()
@ -640,7 +644,7 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
if (this.assistantSessionId is null) if (this.assistantSessionId is null)
return Task.CompletedTask; return Task.CompletedTask;
return this.AssistantSessionService.CheckpointAsync(this.assistantSessionKey, this.assistantSessionId.Value, this.Title, this.ChatThread, this.CaptureAssistantSessionState()); return this.AssistantSessionService.CheckpointAsync(this.assistantSessionKey, this.assistantSessionId.Value, this.Title, this.ChatThread, this.CaptureAssistantSessionState(), this);
} }
/// <summary> /// <summary>
@ -667,6 +671,9 @@ public abstract partial class AssistantBase<TSettings> : AssistantLowerBase wher
/// <returns>A task that completes after the message was processed.</returns> /// <returns>A task that completes after the message was processed.</returns>
protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default protected override async Task ProcessIncomingMessage<T>(ComponentBase? sendingComponent, Event triggeredEvent, T? data) where T : default
{ {
if (ReferenceEquals(sendingComponent, this))
return;
switch (triggeredEvent) switch (triggeredEvent)
{ {
case Event.ASSISTANT_SESSION_CHANGED: case Event.ASSISTANT_SESSION_CHANGED:

View File

@ -2,6 +2,8 @@ using System.Collections.Concurrent;
using AIStudio.Chat; using AIStudio.Chat;
using Microsoft.AspNetCore.Components;
namespace AIStudio.Tools.AssistantSessions; namespace AIStudio.Tools.AssistantSessions;
/// <summary> /// <summary>
@ -148,8 +150,9 @@ public sealed class AssistantSessionService(MessageBus messageBus)
/// <param name="cancellationTokenSource">The cancellation token source owned by the new runtime session.</param> /// <param name="cancellationTokenSource">The cancellation token source owned by the new runtime session.</param>
/// <param name="chatThread">The current assistant chat thread, if one already exists.</param> /// <param name="chatThread">The current assistant chat thread, if one already exists.</param>
/// <param name="state">The initial assistant component state.</param> /// <param name="state">The initial assistant component state.</param>
/// <param name="sendingComponent">The component that initiated the session start.</param>
/// <returns>The new session snapshot, or the existing active session snapshot.</returns> /// <returns>The new session snapshot, or the existing active session snapshot.</returns>
public async Task<AssistantSessionSnapshot> TryBeginAsync(AssistantSessionKey key, string title, CancellationTokenSource cancellationTokenSource, ChatThread? chatThread, Dictionary<string, IAssistantSessionSnapshotField> state) public async Task<AssistantSessionSnapshot> TryBeginAsync(AssistantSessionKey key, string title, CancellationTokenSource cancellationTokenSource, ChatThread? chatThread, Dictionary<string, IAssistantSessionSnapshotField> state, ComponentBase? sendingComponent = null)
{ {
if (this.sessions.TryGetValue(key, out var existing) && existing.Status is AssistantSessionStatus.RUNNING or AssistantSessionStatus.CANCELING) if (this.sessions.TryGetValue(key, out var existing) && existing.Status is AssistantSessionStatus.RUNNING or AssistantSessionStatus.CANCELING)
return CreateSnapshot(existing); return CreateSnapshot(existing);
@ -170,7 +173,7 @@ public sealed class AssistantSessionService(MessageBus messageBus)
this.sessions[key] = session; this.sessions[key] = session;
var snapshot = CreateSnapshot(session); var snapshot = CreateSnapshot(session);
await this.NotifyChangedAsync(session); await this.NotifyChangedAsync(session, sendingComponent);
return snapshot; return snapshot;
} }
@ -182,7 +185,8 @@ public sealed class AssistantSessionService(MessageBus messageBus)
/// <param name="title">The current user-visible assistant title.</param> /// <param name="title">The current user-visible assistant title.</param>
/// <param name="chatThread">The current assistant chat thread.</param> /// <param name="chatThread">The current assistant chat thread.</param>
/// <param name="state">The current assistant component state.</param> /// <param name="state">The current assistant component state.</param>
public async Task CheckpointAsync(AssistantSessionKey key, Guid sessionId, string title, ChatThread? chatThread, Dictionary<string, IAssistantSessionSnapshotField> state) /// <param name="sendingComponent">The component that initiated the checkpoint.</param>
public async Task CheckpointAsync(AssistantSessionKey key, Guid sessionId, string title, ChatThread? chatThread, Dictionary<string, IAssistantSessionSnapshotField> state, ComponentBase? sendingComponent = null)
{ {
if (!this.sessions.TryGetValue(key, out var session)) if (!this.sessions.TryGetValue(key, out var session))
return; return;
@ -198,14 +202,15 @@ public sealed class AssistantSessionService(MessageBus messageBus)
session.UpdatedAt = DateTimeOffset.Now; session.UpdatedAt = DateTimeOffset.Now;
} }
await this.NotifyChangedAsync(session); await this.NotifyChangedAsync(session, sendingComponent);
} }
/// <summary> /// <summary>
/// Requests cancellation for an active assistant session. /// Requests cancellation for an active assistant session.
/// </summary> /// </summary>
/// <param name="key">The assistant session key to cancel.</param> /// <param name="key">The assistant session key to cancel.</param>
public async Task CancelAsync(AssistantSessionKey key) /// <param name="sendingComponent">The component that initiated the cancellation.</param>
public async Task CancelAsync(AssistantSessionKey key, ComponentBase? sendingComponent = null)
{ {
if (!this.sessions.TryGetValue(key, out var session)) if (!this.sessions.TryGetValue(key, out var session))
return; return;
@ -229,7 +234,7 @@ public sealed class AssistantSessionService(MessageBus messageBus)
return; return;
} }
await this.NotifyChangedAsync(session); await this.NotifyChangedAsync(session, sendingComponent);
} }
/// <summary> /// <summary>
@ -241,7 +246,8 @@ public sealed class AssistantSessionService(MessageBus messageBus)
/// <param name="errorMessage">The user-visible error message for failed sessions.</param> /// <param name="errorMessage">The user-visible error message for failed sessions.</param>
/// <param name="chatThread">The final assistant chat thread.</param> /// <param name="chatThread">The final assistant chat thread.</param>
/// <param name="state">The final assistant component state.</param> /// <param name="state">The final assistant component state.</param>
public async Task CompleteAsync(AssistantSessionKey key, Guid sessionId, AssistantSessionStatus status, string errorMessage, ChatThread? chatThread, Dictionary<string, IAssistantSessionSnapshotField> state) /// <param name="sendingComponent">The component that initiated the completion.</param>
public async Task CompleteAsync(AssistantSessionKey key, Guid sessionId, AssistantSessionStatus status, string errorMessage, ChatThread? chatThread, Dictionary<string, IAssistantSessionSnapshotField> state, ComponentBase? sendingComponent = null)
{ {
if (!this.sessions.TryGetValue(key, out var session)) if (!this.sessions.TryGetValue(key, out var session))
return; return;
@ -259,8 +265,8 @@ public sealed class AssistantSessionService(MessageBus messageBus)
session.FinishedAt = session.UpdatedAt; session.FinishedAt = session.UpdatedAt;
} }
await this.NotifyChangedAsync(session); await this.NotifyChangedAsync(session, sendingComponent);
await messageBus.SendMessage(null, Event.ASSISTANT_SESSION_FINISHED, CreateSnapshot(session)); await messageBus.SendMessage(sendingComponent, Event.ASSISTANT_SESSION_FINISHED, CreateSnapshot(session));
try try
{ {
@ -316,9 +322,10 @@ public sealed class AssistantSessionService(MessageBus messageBus)
/// Publishes an assistant session change event. /// Publishes an assistant session change event.
/// </summary> /// </summary>
/// <param name="session">The runtime session whose copied snapshot should be published.</param> /// <param name="session">The runtime session whose copied snapshot should be published.</param>
private async Task NotifyChangedAsync(AssistantSessionState session) /// <param name="sendingComponent">The component that initiated the session change.</param>
private async Task NotifyChangedAsync(AssistantSessionState session, ComponentBase? sendingComponent = null)
{ {
await messageBus.SendMessage(null, Event.ASSISTANT_SESSION_CHANGED, CreateSnapshot(session)); await messageBus.SendMessage(sendingComponent, Event.ASSISTANT_SESSION_CHANGED, CreateSnapshot(session));
} }
/// <summary> /// <summary>