11using System ;
2+ using System . Collections . Generic ;
23using System . Globalization ;
34using System . Linq ;
45using System . Threading ;
@@ -30,6 +31,7 @@ public class MainDialog : RouterDialog
3031 private OnboardingDialog _onboardingDialog ;
3132 private IStatePropertyAccessor < SkillContext > _skillContext ;
3233 private IStatePropertyAccessor < OnboardingState > _onboardingState ;
34+ private IStatePropertyAccessor < List < Activity > > _previousResponseAccessor ;
3335
3436 public MainDialog (
3537 IServiceProvider serviceProvider ,
@@ -41,12 +43,18 @@ public MainDialog(
4143 _templateEngine = serviceProvider . GetService < TemplateEngine > ( ) ;
4244 _langGenerator = serviceProvider . GetService < ILanguageGenerator > ( ) ;
4345 _activityGenerator = serviceProvider . GetService < TextActivityGenerator > ( ) ;
46+ _previousResponseAccessor = serviceProvider . GetService < IStatePropertyAccessor < List < Activity > > > ( ) ;
4447 TelemetryClient = telemetryClient ;
4548
49+ // Create user state properties
4650 var userState = serviceProvider . GetService < UserState > ( ) ;
4751 _onboardingState = userState . CreateProperty < OnboardingState > ( nameof ( OnboardingState ) ) ;
4852 _skillContext = userState . CreateProperty < SkillContext > ( nameof ( SkillContext ) ) ;
4953
54+ // Create conversation state properties
55+ var conversationState = serviceProvider . GetService < ConversationState > ( ) ;
56+ _previousResponseAccessor = conversationState . CreateProperty < List < Activity > > ( "previousResponse" ) ;
57+
5058 // Register dialogs
5159 _onboardingDialog = serviceProvider . GetService < OnboardingDialog > ( ) ;
5260 AddDialog ( _onboardingDialog ) ;
@@ -59,6 +67,13 @@ public MainDialog(
5967 }
6068 }
6169
70+ protected override Task < DialogTurnResult > OnContinueDialogAsync ( DialogContext innerDc , CancellationToken cancellationToken = default )
71+ {
72+ // Set up response caching for "repeat" functionality.
73+ innerDc . Context . OnSendActivities ( StoreOutgoingActivities ) ;
74+ return base . OnContinueDialogAsync ( innerDc , cancellationToken ) ;
75+ }
76+
6277 protected override async Task < InterruptionAction > OnInterruptDialogAsync ( DialogContext dc , CancellationToken cancellationToken )
6378 {
6479 var activity = dc . Context . Activity ;
@@ -126,6 +141,21 @@ protected override async Task<InterruptionAction> OnInterruptDialogAsync(DialogC
126141 // Use this intent to send an event to your device that can turn off the microphone in speech scenarios.
127142 break ;
128143 }
144+
145+ case GeneralLuis . Intent . Repeat :
146+ {
147+ // Sends the activities since the last user message again.
148+ var previousResponse = await _previousResponseAccessor . GetAsync ( dc . Context , ( ) => new List < Activity > ( ) ) ;
149+
150+ foreach ( var response in previousResponse )
151+ {
152+ // Reset id of original activity so it can be processed by the channel.
153+ response . Id = string . Empty ;
154+ await dc . Context . SendActivityAsync ( response ) ;
155+ }
156+
157+ return InterruptionAction . Waiting ;
158+ }
129159 }
130160 }
131161
@@ -298,6 +328,29 @@ private async Task CallQnAMaker(DialogContext innerDc, QnAMaker qnaMaker)
298328 }
299329 }
300330
331+ private async Task < ResourceResponse [ ] > StoreOutgoingActivities ( ITurnContext turnContext , List < Activity > activities , Func < Task < ResourceResponse [ ] > > next )
332+ {
333+ var messageActivities = activities
334+ . Where ( a => a . Type == ActivityTypes . Message )
335+ . ToList ( ) ;
336+
337+ // If the bot is sending message activities to the user (as opposed to trace activities)
338+ if ( messageActivities . Any ( ) )
339+ {
340+ var botResponse = await _previousResponseAccessor . GetAsync ( turnContext , ( ) => new List < Activity > ( ) ) ;
341+
342+ // Get only the activities sent in response to last user message
343+ botResponse = botResponse
344+ . Concat ( messageActivities )
345+ . Where ( a => a . ReplyToId == turnContext . Activity . Id )
346+ . ToList ( ) ;
347+
348+ await _previousResponseAccessor . SetAsync ( turnContext , botResponse ) ;
349+ }
350+
351+ return await next ( ) ;
352+ }
353+
301354 private class Events
302355 {
303356 public const string Location = "VA.Location" ;
0 commit comments