feat(ui): worker client surface for in-app interactive sessions
Adds SendInteractiveMessageAsync/StopInteractiveSessionAsync and the InteractiveSessionStarted/Ended events to IWorkerClient + WorkerClient (UI-thread dispatch mirroring TaskQuestionAsked). Updates the IWorkerClient fakes in both test projects.
This commit is contained in:
@@ -25,6 +25,9 @@ public interface IWorkerClient : INotifyPropertyChanged
|
|||||||
/// <summary>A pending question was answered, timed out, or the run ended: (taskId, questionId).</summary>
|
/// <summary>A pending question was answered, timed out, or the run ended: (taskId, questionId).</summary>
|
||||||
event Action<string, string>? TaskQuestionResolvedEvent;
|
event Action<string, string>? TaskQuestionResolvedEvent;
|
||||||
|
|
||||||
|
event Action<string>? InteractiveSessionStartedEvent;
|
||||||
|
event Action<string>? InteractiveSessionEndedEvent;
|
||||||
|
|
||||||
event Action? PrepStartedEvent;
|
event Action? PrepStartedEvent;
|
||||||
event Action<string>? PrepLineEvent;
|
event Action<string>? PrepLineEvent;
|
||||||
event Action<bool>? PrepFinishedEvent;
|
event Action<bool>? PrepFinishedEvent;
|
||||||
@@ -46,6 +49,8 @@ public interface IWorkerClient : INotifyPropertyChanged
|
|||||||
Task ContinueTaskAsync(string taskId, string followUpPrompt);
|
Task ContinueTaskAsync(string taskId, string followUpPrompt);
|
||||||
/// <summary>Answer a question a running task raised via AskUser.</summary>
|
/// <summary>Answer a question a running task raised via AskUser.</summary>
|
||||||
Task AnswerTaskQuestionAsync(string taskId, string questionId, string answer);
|
Task AnswerTaskQuestionAsync(string taskId, string questionId, string answer);
|
||||||
|
Task SendInteractiveMessageAsync(string taskId, string text);
|
||||||
|
Task StopInteractiveSessionAsync(string taskId);
|
||||||
/// <summary>The question a running task is currently blocked on, if any (for re-attach).</summary>
|
/// <summary>The question a running task is currently blocked on, if any (for re-attach).</summary>
|
||||||
Task<PendingQuestionDto?> GetPendingQuestionAsync(string taskId);
|
Task<PendingQuestionDto?> GetPendingQuestionAsync(string taskId);
|
||||||
Task ResetTaskAsync(string taskId);
|
Task ResetTaskAsync(string taskId);
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
|
|||||||
public event Action<string>? TaskUpdatedEvent;
|
public event Action<string>? TaskUpdatedEvent;
|
||||||
public event Action<string, string, string>? TaskQuestionAskedEvent;
|
public event Action<string, string, string>? TaskQuestionAskedEvent;
|
||||||
public event Action<string, string>? TaskQuestionResolvedEvent;
|
public event Action<string, string>? TaskQuestionResolvedEvent;
|
||||||
|
public event Action<string>? InteractiveSessionStartedEvent;
|
||||||
|
public event Action<string>? InteractiveSessionEndedEvent;
|
||||||
public event Action? ConnectionRestoredEvent;
|
public event Action? ConnectionRestoredEvent;
|
||||||
public event Action<string>? WorktreeUpdatedEvent;
|
public event Action<string>? WorktreeUpdatedEvent;
|
||||||
public event Action<string>? ListUpdatedEvent;
|
public event Action<string>? ListUpdatedEvent;
|
||||||
@@ -148,6 +150,16 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
|
|||||||
Dispatcher.UIThread.Post(() => TaskQuestionResolvedEvent?.Invoke(taskId, questionId));
|
Dispatcher.UIThread.Post(() => TaskQuestionResolvedEvent?.Invoke(taskId, questionId));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_hub.On<string>("InteractiveSessionStarted", taskId =>
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.Post(() => InteractiveSessionStartedEvent?.Invoke(taskId));
|
||||||
|
});
|
||||||
|
|
||||||
|
_hub.On<string>("InteractiveSessionEnded", taskId =>
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.Post(() => InteractiveSessionEndedEvent?.Invoke(taskId));
|
||||||
|
});
|
||||||
|
|
||||||
_hub.On<string>("WorktreeUpdated", taskId =>
|
_hub.On<string>("WorktreeUpdated", taskId =>
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(() => WorktreeUpdatedEvent?.Invoke(taskId));
|
Dispatcher.UIThread.Post(() => WorktreeUpdatedEvent?.Invoke(taskId));
|
||||||
@@ -279,6 +291,18 @@ public partial class WorkerClient : ObservableObject, IAsyncDisposable, IWorkerC
|
|||||||
catch { /* offline or already resolved — the UI clears optimistically */ }
|
catch { /* offline or already resolved — the UI clears optimistically */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task SendInteractiveMessageAsync(string taskId, string text)
|
||||||
|
{
|
||||||
|
try { await _hub.InvokeAsync("SendInteractiveMessage", taskId, text); }
|
||||||
|
catch { /* offline or session already ended */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task StopInteractiveSessionAsync(string taskId)
|
||||||
|
{
|
||||||
|
try { await _hub.InvokeAsync("StopInteractiveSession", taskId); }
|
||||||
|
catch { /* offline */ }
|
||||||
|
}
|
||||||
|
|
||||||
public Task<PendingQuestionDto?> GetPendingQuestionAsync(string taskId)
|
public Task<PendingQuestionDto?> GetPendingQuestionAsync(string taskId)
|
||||||
=> TryInvokeAsync<PendingQuestionDto>("GetPendingQuestion", taskId);
|
=> TryInvokeAsync<PendingQuestionDto>("GetPendingQuestion", taskId);
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ public abstract class StubWorkerClient : IWorkerClient
|
|||||||
public event Action<WorkerLogEntry>? WorkerLogReceivedEvent;
|
public event Action<WorkerLogEntry>? WorkerLogReceivedEvent;
|
||||||
public event Action<string, string, string>? TaskQuestionAskedEvent;
|
public event Action<string, string, string>? TaskQuestionAskedEvent;
|
||||||
public event Action<string, string>? TaskQuestionResolvedEvent;
|
public event Action<string, string>? TaskQuestionResolvedEvent;
|
||||||
|
public event Action<string>? InteractiveSessionStartedEvent;
|
||||||
|
public event Action<string>? InteractiveSessionEndedEvent;
|
||||||
public event Action? PrepStartedEvent;
|
public event Action? PrepStartedEvent;
|
||||||
public event Action<string>? PrepLineEvent;
|
public event Action<string>? PrepLineEvent;
|
||||||
public event Action<bool>? PrepFinishedEvent;
|
public event Action<bool>? PrepFinishedEvent;
|
||||||
@@ -133,6 +135,8 @@ public abstract class StubWorkerClient : IWorkerClient
|
|||||||
public virtual Task SetOnlineInboxConfigAsync(OnlineInboxConfigInputDto input) => Task.CompletedTask;
|
public virtual Task SetOnlineInboxConfigAsync(OnlineInboxConfigInputDto input) => Task.CompletedTask;
|
||||||
public virtual Task SetOnlineInboxAuthAsync(string refreshToken) => Task.CompletedTask;
|
public virtual Task SetOnlineInboxAuthAsync(string refreshToken) => Task.CompletedTask;
|
||||||
public virtual Task ClearOnlineInboxAuthAsync() => Task.CompletedTask;
|
public virtual Task ClearOnlineInboxAuthAsync() => Task.CompletedTask;
|
||||||
|
public virtual Task SendInteractiveMessageAsync(string taskId, string text) => Task.CompletedTask;
|
||||||
|
public virtual Task StopInteractiveSessionAsync(string taskId) => Task.CompletedTask;
|
||||||
|
|
||||||
protected void RaisePropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
protected void RaisePropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ sealed class FakeWorkerClient : IWorkerClient
|
|||||||
public event Action<WorkerLogEntry>? WorkerLogReceivedEvent;
|
public event Action<WorkerLogEntry>? WorkerLogReceivedEvent;
|
||||||
public event Action<string, string, string>? TaskQuestionAskedEvent;
|
public event Action<string, string, string>? TaskQuestionAskedEvent;
|
||||||
public event Action<string, string>? TaskQuestionResolvedEvent;
|
public event Action<string, string>? TaskQuestionResolvedEvent;
|
||||||
|
public event Action<string>? InteractiveSessionStartedEvent;
|
||||||
|
public event Action<string>? InteractiveSessionEndedEvent;
|
||||||
public void RaiseTaskUpdated(string taskId) => TaskUpdatedEvent?.Invoke(taskId);
|
public void RaiseTaskUpdated(string taskId) => TaskUpdatedEvent?.Invoke(taskId);
|
||||||
public void RaiseWorktreeUpdated(string taskId) => WorktreeUpdatedEvent?.Invoke(taskId);
|
public void RaiseWorktreeUpdated(string taskId) => WorktreeUpdatedEvent?.Invoke(taskId);
|
||||||
public void RaiseTaskMessage(string taskId, string line) => TaskMessageEvent?.Invoke(taskId, line);
|
public void RaiseTaskMessage(string taskId, string line) => TaskMessageEvent?.Invoke(taskId, line);
|
||||||
@@ -122,6 +124,8 @@ sealed class FakeWorkerClient : IWorkerClient
|
|||||||
public Task SetOnlineInboxConfigAsync(OnlineInboxConfigInputDto input) => Task.CompletedTask;
|
public Task SetOnlineInboxConfigAsync(OnlineInboxConfigInputDto input) => Task.CompletedTask;
|
||||||
public Task SetOnlineInboxAuthAsync(string refreshToken) => Task.CompletedTask;
|
public Task SetOnlineInboxAuthAsync(string refreshToken) => Task.CompletedTask;
|
||||||
public Task ClearOnlineInboxAuthAsync() => Task.CompletedTask;
|
public Task ClearOnlineInboxAuthAsync() => Task.CompletedTask;
|
||||||
|
public Task SendInteractiveMessageAsync(string taskId, string text) => Task.CompletedTask;
|
||||||
|
public Task StopInteractiveSessionAsync(string taskId) => Task.CompletedTask;
|
||||||
public IReadOnlyList<ActiveTask> GetActiveTasks() => System.Array.Empty<ActiveTask>();
|
public IReadOnlyList<ActiveTask> GetActiveTasks() => System.Array.Empty<ActiveTask>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user