Skip to content

Commit ed3665b

Browse files
authored
Merge branch 'main' into users/rido/teams-samples
2 parents d90be87 + 4aca19f commit ed3665b

File tree

1 file changed

+37
-10
lines changed

1 file changed

+37
-10
lines changed

src/libraries/Builder/Microsoft.Agents.Builder/StreamingResponse.cs

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using Microsoft.Agents.Builder.Errors;
55
using Microsoft.Agents.Core;
6+
using Microsoft.Agents.Core.Errors;
67
using Microsoft.Agents.Core.Models;
78
using System;
89
using System.Collections.Generic;
@@ -40,13 +41,16 @@ internal class StreamingResponse : IStreamingResponse
4041
{
4142
public static readonly int DefaultEndStreamTimeout = (int)TimeSpan.FromMinutes(2).TotalMilliseconds;
4243

44+
private const string TeamsStreamCancelled = "ContentStreamNotAllowed";
45+
4346
private readonly TurnContext _context;
4447
private int _nextSequence = 1;
4548
private bool _ended = false;
4649
private Timer _timer;
4750
private bool _messageUpdated = false;
4851
private bool _informativeSent = false;
4952
private bool _isTeamsChannel;
53+
private bool _cancelled;
5054

5155
// Queue for outgoing activities
5256
private readonly List<Func<IActivity>> _queue = [];
@@ -211,7 +215,7 @@ public async Task QueueInformativeUpdateAsync(string text, CancellationToken can
211215
/// <exception cref="System.InvalidOperationException">Throws if the stream has already ended.</exception>
212216
public void QueueTextChunk(string text)
213217
{
214-
if (string.IsNullOrEmpty(text))
218+
if (string.IsNullOrEmpty(text) || _cancelled)
215219
{
216220
return;
217221
}
@@ -264,7 +268,7 @@ public async Task EndStreamAsync(CancellationToken cancellationToken = default)
264268
}
265269

266270
// Timer isn't running for non-streaming channels. Just send the Message buffer as a message.
267-
if (!string.IsNullOrWhiteSpace(Message) || FinalMessage != null)
271+
if (UpdatesSent() > 0 || FinalMessage != null)
268272
{
269273
await _context.SendActivityAsync(CreateFinalMessage(), cancellationToken).ConfigureAwait(false);
270274
}
@@ -280,7 +284,7 @@ public async Task EndStreamAsync(CancellationToken cancellationToken = default)
280284

281285
_ended = true;
282286

283-
if (UpdatesSent() == 0)
287+
if (UpdatesSent() == 0 || _cancelled)
284288
{
285289
// nothing was queued. nothing to "end".
286290
return;
@@ -300,7 +304,7 @@ public async Task EndStreamAsync(CancellationToken cancellationToken = default)
300304
}
301305
}
302306

303-
if (!string.IsNullOrEmpty(Message) || FinalMessage != null)
307+
if (UpdatesSent() > 0 || FinalMessage != null)
304308
{
305309
await SendActivityAsync(CreateFinalMessage(), cancellationToken).ConfigureAwait(false);
306310
}
@@ -312,7 +316,7 @@ private IActivity CreateFinalMessage()
312316
var activity = FinalMessage ?? new Activity();
313317

314318
activity.Type = ActivityTypes.Message;
315-
activity.Text = Message; // Teams won't allow Activity.Text changes
319+
activity.Text = Message; // !string.IsNullOrEmpty(Message) ? Message : "No text was streamed"; // Teams won't allow Activity.Text changes or empty text
316320
activity.Entities ??= [];
317321

318322
// make sure the supplied Activity doesn't have a streamInfo already.
@@ -325,7 +329,7 @@ private IActivity CreateFinalMessage()
325329
}
326330
}
327331

328-
activity.Entities.Add(new StreamInfo() { StreamType = StreamTypes.Final });
332+
activity.Entities.Add(new StreamInfo() { StreamType = StreamTypes.Final, StreamResult = (string.IsNullOrEmpty(Message) ? StreamResults.Error : StreamResults.Success) });
329333

330334
// Add in Generated by AI
331335
if (EnableGeneratedByAILabel == true)
@@ -367,6 +371,7 @@ public async Task ResetAsync(CancellationToken cancellationToken = default)
367371
FinalMessage = null;
368372
_nextSequence = 1;
369373
StreamId = null;
374+
_cancelled = false;
370375
}
371376
}
372377

@@ -527,11 +532,33 @@ private async Task SendActivityAsync(IActivity activity, CancellationToken cance
527532
activity.GetStreamingEntity().StreamId = StreamId;
528533
}
529534

530-
var response = await _context.SendActivityAsync(activity, cancellationToken).ConfigureAwait(false);
531-
532-
if (string.IsNullOrEmpty(StreamId))
535+
try
536+
{
537+
var response = await _context.SendActivityAsync(activity, cancellationToken).ConfigureAwait(false);
538+
if (string.IsNullOrEmpty(StreamId))
539+
{
540+
StreamId = response.Id;
541+
}
542+
}
543+
catch (Exception ex)
533544
{
534-
StreamId = response.Id;
545+
// We are not rethrowing from here since this is likely being called
546+
// from the Timer thread and will crash the app. A more elegant
547+
// solution would be to get it back to the calling thread.
548+
549+
if (ex is ErrorResponseException errorResponse)
550+
{
551+
if (!TeamsStreamCancelled.Equals(errorResponse.Body.Error.Code, StringComparison.OrdinalIgnoreCase))
552+
{
553+
System.Diagnostics.Trace.WriteLine($"Exception during StreamingResponse: {ex.Message}");
554+
}
555+
}
556+
557+
lock (this)
558+
{
559+
StopStream();
560+
_cancelled = true;
561+
}
535562
}
536563
}
537564
}

0 commit comments

Comments
 (0)