diff --git a/app/MindWork AI Studio/Provider/BaseProvider.cs b/app/MindWork AI Studio/Provider/BaseProvider.cs index b2e4eb1ad..eddb53ade 100644 --- a/app/MindWork AI Studio/Provider/BaseProvider.cs +++ b/app/MindWork AI Studio/Provider/BaseProvider.cs @@ -1007,22 +1007,12 @@ public abstract class BaseProvider : IProvider, ISecretId try { // - // Read the stream, line by line: + // Read the stream, line by line, until it ends. We never ask the reader whether the + // stream ended: that would wait for the next data without any timeout, and it would + // hold a thread meanwhile. Reading the next line tells the same, see below. // while (true) { - try - { - if(streamReader.EndOfStream) - break; - } - catch (Exception e) - { - await MessageBus.INSTANCE.SendError(new(Icons.Material.Filled.Stream, string.Format(TB("Tried to stream the LLM provider '{0}' answer. There were some problems with the stream. The message is: '{1}'"), this.InstanceName, e.Message))); - this.logger.LogWarning(e, "Failed to read the end-of-stream state from {ProviderName} '{ProviderInstanceName}': {ErrorMessage}", providerName, this.InstanceName, e.Message); - break; - } - // Check if the token is canceled: if (token.IsCancellationRequested) { @@ -1058,13 +1048,14 @@ public abstract class BaseProvider : IProvider, ISecretId break; } + // The stream ended: if (line is null) break; // Skip empty lines: if (string.IsNullOrWhiteSpace(line)) continue; - + if (this.TryCreateProviderRequestExceptionFromStreamLine(providerName, line, out var providerRequestException)) throw providerRequestException; diff --git a/app/MindWork AI Studio/Tools/Services/RustService.Events.cs b/app/MindWork AI Studio/Tools/Services/RustService.Events.cs index 67c6bb09f..ca93739d8 100644 --- a/app/MindWork AI Studio/Tools/Services/RustService.Events.cs +++ b/app/MindWork AI Studio/Tools/Services/RustService.Events.cs @@ -27,12 +27,9 @@ public partial class RustService // Read events line by line: using var reader = new StreamReader(stream); - // Read until the end of the stream or cancellation: - while(!reader.EndOfStream && !stopToken.IsCancellationRequested) + // Read the next line of JSON until the end of the stream or cancellation: + while(!stopToken.IsCancellationRequested && await reader.ReadLineAsync(stopToken) is { } line) { - // Read the next line of JSON from the stream: - var line = await reader.ReadLineAsync(stopToken); - // Skip empty lines: if (string.IsNullOrWhiteSpace(line)) continue; diff --git a/app/MindWork AI Studio/Tools/Services/RustService.Retrieval.cs b/app/MindWork AI Studio/Tools/Services/RustService.Retrieval.cs index 8891649a0..220a72105 100644 --- a/app/MindWork AI Studio/Tools/Services/RustService.Retrieval.cs +++ b/app/MindWork AI Studio/Tools/Services/RustService.Retrieval.cs @@ -352,9 +352,8 @@ public sealed partial class RustService await using var stream = await response.Content.ReadAsStreamAsync(token); using var reader = new StreamReader(stream); - while (!reader.EndOfStream && !token.IsCancellationRequested) + while (!token.IsCancellationRequested && await reader.ReadLineAsync(token) is { } line) { - var line = await reader.ReadLineAsync(token); if (string.IsNullOrWhiteSpace(line)) continue;