Skip to content
This repository has been archived by the owner on Jun 30, 2022. It is now read-only.

Commit

Permalink
[Lib] Refactored routerDialog (#2458)
Browse files Browse the repository at this point in the history
* refactored routerDialog

* updated method documentation
  • Loading branch information
lauren-mills authored and darrenj committed Oct 2, 2019
1 parent dd32c7a commit 92af3db
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ public class CognitiveModelSet
{
public IRecognizer DispatchService { get; set; }

public Dictionary<string, ITelemetryRecognizer> LuisServices { get; set; } = new Dictionary<string, ITelemetryRecognizer>();
public Dictionary<string, LuisRecognizer> LuisServices { get; set; } = new Dictionary<string, LuisRecognizer>();

public Dictionary<string, ITelemetryQnAMaker> QnAServices { get; set; } = new Dictionary<string, ITelemetryQnAMaker>();
public Dictionary<string, QnAMaker> QnAServices { get; set; } = new Dictionary<string, QnAMaker>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogCont
{
var status = await OnInterruptDialogAsync(dc, cancellationToken).ConfigureAwait(false);

if (status == InterruptionAction.MessageSentToUser)
if (status == InterruptionAction.Resume)
{
// Resume the waiting dialog after interruption
await dc.RepromptDialogAsync().ConfigureAwait(false);
return EndOfTurn;
}
else if (status == InterruptionAction.StartedDialog)
else if (status == InterruptionAction.Waiting)
{
// Stack is already waiting for a response, shelve inner stack
return EndOfTurn;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,25 @@

namespace Microsoft.Bot.Builder.Solutions.Dialogs
{
/// <summary>
/// Indicates the current status of a dialog interruption.
/// </summary>
public enum InterruptionAction
{
/// <summary>
/// Indicates that the active dialog was interrupted and should end.
/// </summary>
End,

/// <summary>
/// Indicates that the active dialog was interrupted and needs to resume.
/// </summary>
MessageSentToUser,
Resume,

/// <summary>
/// Indicates that there is a new dialog waiting and the active dialog needs to be shelved.
/// </summary>
StartedDialog,
Waiting,

/// <summary>
/// Indicates that no interruption action is required.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Threading;
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Solutions.Extensions;
Expand All @@ -14,176 +15,156 @@ public RouterDialog(string dialogId, IBotTelemetryClient telemetryClient)
TelemetryClient = telemetryClient;
}

protected override Task<DialogTurnResult> OnBeginDialogAsync(DialogContext innerDc, object options, CancellationToken cancellationToken = default(CancellationToken))
protected override Task<DialogTurnResult> OnBeginDialogAsync(DialogContext innerDc, object options, CancellationToken cancellationToken = default)
{
return OnContinueDialogAsync(innerDc, cancellationToken);
}

protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
protected override async Task<DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default)
{
// Check for any interruptions.
var status = await OnInterruptDialogAsync(innerDc, cancellationToken).ConfigureAwait(false);

if (status == InterruptionAction.MessageSentToUser)
if (status == InterruptionAction.Resume)
{
// Resume the waiting dialog after interruption
// Interruption message was sent, and the waiting dialog should resume/reprompt.
await innerDc.RepromptDialogAsync().ConfigureAwait(false);
return EndOfTurn;
}
else if (status == InterruptionAction.StartedDialog)
else if (status == InterruptionAction.Waiting)
{
// Stack is already waiting for a response, shelve inner stack
// Interruption intercepted conversation and is waiting for user to respond.
return EndOfTurn;
}
else
else if (status == InterruptionAction.End)
{
// Interruption ended conversation, and current dialog should end.
return await innerDc.EndDialogAsync().ConfigureAwait(false);
}
else if (status == InterruptionAction.NoAction)
{
// No interruption was detected. Process activity normally.
var activity = innerDc.Context.Activity;

if (activity.IsStartActivity())
{
await OnStartAsync(innerDc).ConfigureAwait(false);
}

switch (activity.Type)
{
case ActivityTypes.Message:
{
// Note: This check is a workaround for adaptive card buttons that should map to an event (i.e. startOnboarding button in intro card)
if (activity.Value != null)
{
await OnEventAsync(innerDc).ConfigureAwait(false);
}
else
{
var result = await innerDc.ContinueDialogAsync().ConfigureAwait(false);

switch (result.Status)
{
case DialogTurnStatus.Empty:
{
await RouteAsync(innerDc).ConfigureAwait(false);
break;
}

case DialogTurnStatus.Complete:
{
if (result.Result is RouterDialogTurnResult routerDialogTurnResult && routerDialogTurnResult.Status == RouterDialogTurnStatus.Restart)
{
await RouteAsync(innerDc).ConfigureAwait(false);
break;
}

// End active dialog
await innerDc.EndDialogAsync().ConfigureAwait(false);
break;
}

default:
{
break;
}
}
}
// Pass message to waiting child dialog.
var result = await innerDc.ContinueDialogAsync().ConfigureAwait(false);

// If the active dialog was ended on this turn (either on single-turn dialog, or on continueDialogAsync) run CompleteAsync method.
if (innerDc.ActiveDialog == null)
if (result.Status == DialogTurnStatus.Empty
|| (result.Result is RouterDialogTurnResult routerDialogTurnResult && routerDialogTurnResult.Status == RouterDialogTurnStatus.Restart))
{
await CompleteAsync(innerDc).ConfigureAwait(false);
// There was no waiting dialog on the stack, process message normally.
await OnMessageActivityAsync(innerDc).ConfigureAwait(false);
}

break;
}

case ActivityTypes.Event:
{
await OnEventAsync(innerDc).ConfigureAwait(false);
await OnEventActivityAsync(innerDc).ConfigureAwait(false);
break;
}

case ActivityTypes.Invoke:
case ActivityTypes.ConversationUpdate:
{
// Used by Teams for Authentication scenarios.
await innerDc.ContinueDialogAsync().ConfigureAwait(false);
await OnMembersAddedAsync(innerDc).ConfigureAwait(false);
break;
}

default:
{
await OnSystemMessageAsync(innerDc).ConfigureAwait(false);
// All other activity types will be routed here. Custom handling should be added in implementation.
await OnUnhandledActivityTypeAsync(innerDc).ConfigureAwait(false);
break;
}
}
}

return EndOfTurn;
if (innerDc.ActiveDialog == null)
{
// If the inner dialog stack completed during this turn, this component should be ended.
return await innerDc.EndDialogAsync().ConfigureAwait(false);
}
}

protected override Task OnEndDialogAsync(ITurnContext context, DialogInstance instance, DialogReason reason, CancellationToken cancellationToken = default(CancellationToken))
{
return base.OnEndDialogAsync(context, instance, reason, cancellationToken);
return EndOfTurn;
}

protected override Task OnRepromptDialogAsync(ITurnContext turnContext, DialogInstance instance, CancellationToken cancellationToken = default(CancellationToken))
protected override async Task<DialogTurnResult> EndComponentAsync(DialogContext outerDc, object result, CancellationToken cancellationToken)
{
return base.OnRepromptDialogAsync(turnContext, instance, cancellationToken);
// This happens when an inner dialog ends. Could call complete here
await OnDialogCompleteAsync(outerDc, result, cancellationToken).ConfigureAwait(false);
return await base.EndComponentAsync(outerDc, result, cancellationToken).ConfigureAwait(false);
}

/// <summary>
/// Called when the inner dialog stack is empty.
/// Called on every turn, enabling interruption scenarios.
/// </summary>
/// <param name="innerDc">The dialog context for the component.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
protected abstract Task RouteAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken));
/// <returns>A <see cref="Task"/> returning an <see cref="InterruptionAction">
/// which indicates what action should be taken after interruption.</returns>.
protected override Task<InterruptionAction> OnInterruptDialogAsync(DialogContext innerDc, CancellationToken cancellationToken)
{
return Task.FromResult(InterruptionAction.NoAction);
}

/// <summary>
/// Called when the inner dialog stack is complete.
/// Called when an event activity is received.
/// </summary>
/// <param name="innerDc">The dialog context for the component.</param>
/// <param name="result">The dialog result when inner dialog completed.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
protected virtual Task CompleteAsync(DialogContext innerDc, DialogTurnResult result = null, CancellationToken cancellationToken = default(CancellationToken))
protected virtual Task OnEventActivityAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
{
innerDc.EndDialogAsync(result).Wait(cancellationToken);
return Task.CompletedTask;
}

/// <summary>
/// Called when an event activity is received.
/// Called when a message activity is received.
/// </summary>
/// <param name="innerDc">The dialog context for the component.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
protected virtual Task OnEventAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
protected virtual Task OnMessageActivityAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.CompletedTask;
}

/// <summary>
/// Called when a system activity is received.
/// Called when a conversationUpdate activity is received.
/// </summary>
/// <param name="innerDc">The dialog context for the component.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
protected virtual Task OnSystemMessageAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
protected virtual Task OnMembersAddedAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.CompletedTask;
}

/// <summary>
/// Called when a conversation update activity is received.
/// Called when an activity type other than event, message, or conversationUpdate is received.
/// </summary>
/// <param name="innerDc">The dialog context for the component.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
protected virtual Task OnStartAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
protected virtual Task OnUnhandledActivityTypeAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
{
return Task.CompletedTask;
}

protected override Task<InterruptionAction> OnInterruptDialogAsync(DialogContext dc, CancellationToken cancellationToken = default(CancellationToken))
/// <summary>
/// Called when the inner dialog stack completes.
/// </summary>
/// <param name="outerDc">The dialog context for the component.</param>
/// <param name="result">The dialog turn result for the component.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
protected virtual Task OnDialogCompleteAsync(DialogContext outerDc, object result, CancellationToken cancellationToken)
{
return Task.FromResult(InterruptionAction.NoAction);
return Task.CompletedTask;
}
}
}
}

0 comments on commit 92af3db

Please sign in to comment.