コード例 #1
0
 /// <summary>
 /// Called when the dialog is started and pushed onto the parent's dialog stack.
 /// </summary>
 /// <param name="innerDc">The inner <see cref="DialogContext"/> for the current turn of conversation.</param>
 /// <param name="options">Optional, initial information to pass to the dialog.</param>
 /// <param name="cancellationToken">A cancellation token that can be used by other objects
 /// or threads to receive notice of cancellation.</param>
 /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
 /// <remarks>If the task is successful, the result indicates whether the dialog is still
 /// active after the turn has been processed by the dialog.
 ///
 /// By default, this calls the
 /// <see cref="Dialog.BeginDialogAsync(DialogContext, object, CancellationToken)"/> method
 /// of the component dialog's initial dialog, as defined by <see cref="InitialDialogId"/>.
 ///
 /// Override this method in a derived class to implement interrupt logic.</remarks>
 /// <seealso cref="BeginDialogAsync(DialogContext, object, CancellationToken)"/>
 protected virtual Task <DialogTurnResult> OnBeginDialogAsync(DialogContext innerDc, object options, CancellationToken cancellationToken = default(CancellationToken))
 {
     return(innerDc.BeginDialogAsync(InitialDialogId, options, cancellationToken));
 }
コード例 #2
0
        /// <summary>
        /// Runs dialog system in the context of an ITurnContext.
        /// </summary>
        /// <param name="context">turn context.</param>
        /// <param name="cancellationToken">cancelation token.</param>
        /// <returns>result of the running the logic against the activity.</returns>
        public async Task <DialogManagerResult> OnTurnAsync(ITurnContext context, CancellationToken cancellationToken = default(CancellationToken))
        {
            var botStateSet = new BotStateSet();

            // preload turnstate with DM turnstate
            foreach (var pair in this.TurnState)
            {
                context.TurnState.Set(pair.Key, pair.Value);
            }

            if (this.ConversationState == null)
            {
                this.ConversationState = context.TurnState.Get <ConversationState>() ?? throw new ArgumentNullException(nameof(this.ConversationState));
            }
            else
            {
                context.TurnState.Set(this.ConversationState);
            }

            botStateSet.Add(this.ConversationState);

            if (this.UserState == null)
            {
                this.UserState = context.TurnState.Get <UserState>();
            }

            if (this.UserState != null)
            {
                botStateSet.Add(this.UserState);
            }

            // create property accessors
            var lastAccessProperty = ConversationState.CreateProperty <DateTime>(LASTACCESS);
            var lastAccess         = await lastAccessProperty.GetAsync(context, () => DateTime.UtcNow, cancellationToken : cancellationToken).ConfigureAwait(false);

            // Check for expired conversation
            var now = DateTime.UtcNow;

            if (this.ExpireAfter.HasValue && (DateTime.UtcNow - lastAccess) >= TimeSpan.FromMilliseconds((double)this.ExpireAfter))
            {
                // Clear conversation state
                await ConversationState.ClearStateAsync(context, cancellationToken : cancellationToken).ConfigureAwait(false);
            }

            lastAccess = DateTime.UtcNow;
            await lastAccessProperty.SetAsync(context, lastAccess, cancellationToken : cancellationToken).ConfigureAwait(false);

            // get dialog stack
            var         dialogsProperty = ConversationState.CreateProperty <DialogState>(this.dialogStateProperty);
            DialogState dialogState     = await dialogsProperty.GetAsync(context, () => new DialogState(), cancellationToken : cancellationToken).ConfigureAwait(false);

            // Create DialogContext
            var dc = new DialogContext(this.Dialogs, context, dialogState);

            // get the dialogstatemanager configuration
            var dialogStateManager = new DialogStateManager(dc);
            await dialogStateManager.LoadAllScopesAsync(cancellationToken).ConfigureAwait(false);

            dc.Context.TurnState.Add(dialogStateManager);

            DialogTurnResult turnResult = null;

            // Loop as long as we are getting valid OnError handled we should continue executing the actions for the turn.
            //
            // NOTE: We loop around this block because each pass through we either complete the turn and break out of the loop
            // or we have had an exception AND there was an OnError action which captured the error.  We need to continue the
            // turn based on the actions the OnError handler introduced.
            while (true)
            {
                try
                {
                    if (dc.ActiveDialog == null)
                    {
                        // start root dialog
                        turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        // Continue execution
                        // - This will apply any queued up interruptions and execute the current/next step(s).
                        turnResult = await dc.ContinueDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false);

                        if (turnResult.Status == DialogTurnStatus.Empty)
                        {
                            // restart root dialog
                            turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
                        }
                    }

                    // turn successfully completed, break the loop
                    break;
                }
                catch (Exception err)
                {
                    // fire error event, bubbling from the leaf.
                    var handled = await dc.EmitEventAsync(DialogEvents.Error, err, bubble : true, fromLeaf : true, cancellationToken : cancellationToken).ConfigureAwait(false);

                    if (!handled)
                    {
                        // error was NOT handled, throw the exception and end the turn. (This will trigger the Adapter.OnError handler and end the entire dialog stack)
                        throw;
                    }
                }
            }

            // save all state scopes to their respective botState locations.
            await dc.GetState().SaveAllChangesAsync(cancellationToken).ConfigureAwait(false);

            // save botstate changes
            await botStateSet.SaveAllChangesAsync(dc.Context, false, cancellationToken).ConfigureAwait(false);

            // send trace of memory
            var snapshot      = dc.GetState().GetMemorySnapshot();
            var traceActivity = (Activity)Activity.CreateTraceActivity("BotState", "https://www.botframework.com/schemas/botState", snapshot, "Bot State");
            await dc.Context.SendActivityAsync(traceActivity).ConfigureAwait(false);

            return(new DialogManagerResult()
            {
                TurnResult = turnResult
            });
        }
コード例 #3
0
        /// <summary>
        /// Runs dialog system in the context of an ITurnContext.
        /// </summary>
        /// <param name="context">turn context.</param>
        /// <param name="cancellationToken">cancelation token.</param>
        /// <returns>result of the running the logic against the activity.</returns>
        public async Task <DialogManagerResult> OnTurnAsync(ITurnContext context, CancellationToken cancellationToken = default(CancellationToken))
        {
            BotStateSet       botStateSet       = new BotStateSet();
            ConversationState conversationState = this.ConversationState ?? context.TurnState.Get <ConversationState>() ?? throw new ArgumentNullException($"{nameof(ConversationState)} is not found in the turn context. Have you called adapter.UseState() with a configured ConversationState object?");
            UserState         userState         = this.UserState ?? context.TurnState.Get <UserState>();

            if (conversationState != null)
            {
                botStateSet.Add(conversationState);
            }

            if (userState != null)
            {
                botStateSet.Add(userState);
            }

            // create property accessors
            var lastAccessProperty = conversationState.CreateProperty <DateTime>(LASTACCESS);
            var lastAccess         = await lastAccessProperty.GetAsync(context, () => DateTime.UtcNow, cancellationToken : cancellationToken).ConfigureAwait(false);

            // Check for expired conversation
            var now = DateTime.UtcNow;

            if (this.ExpireAfter.HasValue && (DateTime.UtcNow - lastAccess) >= TimeSpan.FromMilliseconds((double)this.ExpireAfter))
            {
                // Clear conversation state
                await conversationState.ClearStateAsync(context, cancellationToken : cancellationToken).ConfigureAwait(false);
            }

            lastAccess = DateTime.UtcNow;
            await lastAccessProperty.SetAsync(context, lastAccess, cancellationToken : cancellationToken).ConfigureAwait(false);

            // get dialog stack
            var         dialogsProperty = conversationState.CreateProperty <DialogState>(DIALOGS);
            DialogState dialogState     = await dialogsProperty.GetAsync(context, () => new DialogState(), cancellationToken : cancellationToken).ConfigureAwait(false);

            // Create DialogContext
            var dc = new DialogContext(this.dialogSet, context, dialogState);

            // set DSM configuration
            dc.SetStateConfiguration(this.StateConfiguration ?? DialogStateManager.CreateStandardConfiguration(conversationState, userState));

            // load scopes
            await dc.GetState().LoadAllScopesAsync(cancellationToken).ConfigureAwait(false);

            DialogTurnResult turnResult = null;

            if (dc.ActiveDialog == null)
            {
                // start root dialog
                turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
            }
            else
            {
                // Continue execution
                // - This will apply any queued up interruptions and execute the current/next step(s).
                turnResult = await dc.ContinueDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false);

                if (turnResult.Status == DialogTurnStatus.Empty)
                {
                    // restart root dialog
                    turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
                }
            }

            // save all state scopes to their respective stores.
            await dc.GetState().SaveAllChangesAsync(cancellationToken).ConfigureAwait(false);

            // save botstate changes
            await botStateSet.SaveAllChangesAsync(dc.Context, false, cancellationToken).ConfigureAwait(false);

            // send trace of memory
            var snapshot      = dc.GetState().GetMemorySnapshot();
            var traceActivity = (Activity)Activity.CreateTraceActivity("BotState", "https://www.botframework.com/schemas/botState", snapshot, "Bot State");
            await dc.Context.SendActivityAsync(traceActivity).ConfigureAwait(false);

            return(new DialogManagerResult()
            {
                TurnResult = turnResult
            });
        }
コード例 #4
0
        private static async Task <DialogTurnResult> InnerRunAsync(ITurnContext turnContext, string dialogId, DialogContext dialogContext, CancellationToken cancellationToken)
        {
            // Handle EoC and Reprompt event from a parent bot (can be root bot to skill or skill to skill)
            if (IsFromParentToSkill(turnContext))
            {
                // Handle remote cancellation request from parent.
                if (turnContext.Activity.Type == ActivityTypes.EndOfConversation)
                {
                    if (!dialogContext.Stack.Any())
                    {
                        // No dialogs to cancel, just return.
                        return(new DialogTurnResult(DialogTurnStatus.Empty));
                    }

                    var activeDialogContext = GetActiveDialogContext(dialogContext);

                    // Send cancellation message to the top dialog in the stack to ensure all the parents are canceled in the right order.
                    return(await activeDialogContext.CancelAllDialogsAsync(true, cancellationToken : cancellationToken).ConfigureAwait(false));
                }

                // Handle a reprompt event sent from the parent.
                if (turnContext.Activity.Type == ActivityTypes.Event && turnContext.Activity.Name == DialogEvents.RepromptDialog)
                {
                    if (!dialogContext.Stack.Any())
                    {
                        // No dialogs to reprompt, just return.
                        return(new DialogTurnResult(DialogTurnStatus.Empty));
                    }

                    await dialogContext.RepromptDialogAsync(cancellationToken).ConfigureAwait(false);

                    return(new DialogTurnResult(DialogTurnStatus.Waiting));
                }
            }

            // Continue or start the dialog.
            var result = await dialogContext.ContinueDialogAsync(cancellationToken).ConfigureAwait(false);

            if (result.Status == DialogTurnStatus.Empty)
            {
                result = await dialogContext.BeginDialogAsync(dialogId, null, cancellationToken).ConfigureAwait(false);
            }

            await SendStateSnapshotTraceAsync(dialogContext, cancellationToken).ConfigureAwait(false);

            // Skills should send EoC when the dialog completes.
            if (result.Status == DialogTurnStatus.Complete || result.Status == DialogTurnStatus.Cancelled)
            {
                if (SendEoCToParent(turnContext))
                {
                    // Send End of conversation at the end.
                    var code     = result.Status == DialogTurnStatus.Complete ? EndOfConversationCodes.CompletedSuccessfully : EndOfConversationCodes.UserCancelled;
                    var activity = new Activity(ActivityTypes.EndOfConversation)
                    {
                        Value = result.Result, Locale = turnContext.Activity.Locale, Code = code
                    };
                    await turnContext.SendActivityAsync(activity, cancellationToken).ConfigureAwait(false);
                }
            }

            return(result);
        }
コード例 #5
0
        /// <summary>
        /// Runs dialog system in the context of an ITurnContext.
        /// </summary>
        /// <param name="context">turn context.</param>
        /// <param name="state">stored state.</param>
        /// <param name="cancellationToken">cancelation token.</param>
        /// <returns>result of the running the logic against the activity.</returns>
        public async Task <DialogManagerResult> OnTurnAsync(ITurnContext context, PersistedState state = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            var saveState = false;
            var keys      = GetKeys(context);
            var storage   = context.TurnState.Get <IStorage>();

            if (state == null)
            {
                if (storage == null)
                {
                    throw new Exception("DialogManager: unable to load the bots state.Bot.storage not assigned.");
                }

                state = await LoadStateAsync(storage, keys).ConfigureAwait(false);

                saveState = true;
            }

            // Clone state to preserve original state
            var newState = ObjectPath.Clone(state);

            // Check for expired conversation
            var now = DateTime.UtcNow;

            if (this.ExpireAfter.HasValue && newState.ConversationState.ContainsKey(LASTACCESS))
            {
                var lastAccess = DateTime.Parse(newState.ConversationState[LASTACCESS] as string);
                if ((DateTime.UtcNow - lastAccess) >= TimeSpan.FromMilliseconds((double)this.ExpireAfter))
                {
                    // Clear conversation state
                    state.ConversationState       = new Dictionary <string, object>();
                    state.ConversationState[ETAG] = newState.ConversationState[ETAG];
                }
            }

            newState.ConversationState[LASTACCESS] = DateTime.UtcNow.ToString("u");

            // Ensure dialog stack populated
            DialogState dialogState;

            if (!newState.ConversationState.ContainsKey(DIALOGS))
            {
                dialogState = new DialogState();
                newState.ConversationState[DIALOGS] = dialogState;
            }
            else
            {
                dialogState = (DialogState)newState.ConversationState[DIALOGS];
            }

            var namedScopes = MemoryScope.GetScopesMemory(context);

            namedScopes[ScopePath.USER]         = newState.UserState;
            namedScopes[ScopePath.CONVERSATION] = newState.ConversationState;
            namedScopes[ScopePath.TURN]         = new Dictionary <string, object>(StringComparer.InvariantCultureIgnoreCase);

            // Create DialogContext
            var dc = new DialogContext(
                this.dialogSet,
                context,
                dialogState);

            DialogTurnResult turnResult = null;

            if (dc.ActiveDialog == null)
            {
                // start root dialog
                turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
            }
            else
            {
                // Continue execution
                // - This will apply any queued up interruptions and execute the current/next step(s).
                turnResult = await dc.ContinueDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false);

                if (turnResult.Status == DialogTurnStatus.Empty)
                {
                    // restart root dialog
                    turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
                }
            }

            // send trace of memory
            await dc.Context.SendActivityAsync((Activity)Activity.CreateTraceActivity("BotState", "https://www.botframework.com/schemas/botState", dc.State.GetMemorySnapshot(), "Bot State")).ConfigureAwait(false);

            // Save state if loaded from storage
            if (saveState)
            {
                await DialogManager.SaveStateAsync(storage, keys : keys, newState : newState, oldState : state, eTag : "*").ConfigureAwait(false);

                return(new DialogManagerResult()
                {
                    TurnResult = turnResult
                });
            }
            else
            {
                return(new DialogManagerResult()
                {
                    TurnResult = turnResult, NewState = newState
                });
            }
        }
コード例 #6
0
        /// <summary>
        /// Runs dialog system in the context of an ITurnContext.
        /// </summary>
        /// <param name="context">turn context.</param>
        /// <param name="cancellationToken">cancelation token.</param>
        /// <returns>result of the running the logic against the activity.</returns>
        public async Task <DialogManagerResult> OnTurnAsync(ITurnContext context, CancellationToken cancellationToken = default(CancellationToken))
        {
            ConversationState conversationState = context.TurnState.Get <ConversationState>() ?? throw new ArgumentNullException($"{nameof(ConversationState)} is not found in the turn context. Have you called adapter.UseState() with a configured ConversationState object?");
            UserState         userState         = context.TurnState.Get <UserState>() ?? throw new ArgumentNullException($"{nameof(UserState)} is not found in the turn context. Have you called adapter.UseState() with a configured UserState object?");

            // create property accessors
            var lastAccessProperty = conversationState.CreateProperty <DateTime>(LASTACCESS);
            var dialogsProperty    = conversationState.CreateProperty <DialogState>(DIALOGS);
            var userScope          = userState.CreateProperty <object>($"{ScopePath.USER}{nameof(MemoryScope)}");
            var conversationScope  = conversationState.CreateProperty <object>($"{ScopePath.CONVERSATION}{nameof(MemoryScope)}");

            var lastAccess = await lastAccessProperty.GetAsync(context, () => DateTime.UtcNow, cancellationToken : cancellationToken).ConfigureAwait(false);

            // Check for expired conversation
            var now = DateTime.UtcNow;

            if (this.ExpireAfter.HasValue && (DateTime.UtcNow - lastAccess) >= TimeSpan.FromMilliseconds((double)this.ExpireAfter))
            {
                // Clear conversation state
                await conversationState.ClearStateAsync(context, cancellationToken : cancellationToken).ConfigureAwait(false);
            }

            lastAccess = DateTime.UtcNow;
            await lastAccessProperty.SetAsync(context, lastAccess, cancellationToken : cancellationToken).ConfigureAwait(false);

            // get dialog stack
            DialogState dialogState = await dialogsProperty.GetAsync(context, () => new DialogState(), cancellationToken : cancellationToken).ConfigureAwait(false);

            var namedScopes = MemoryScope.GetScopesMemory(context);

            namedScopes[ScopePath.USER] = await userScope.GetAsync(context, () => new Dictionary <string, object>(StringComparer.InvariantCultureIgnoreCase), cancellationToken : cancellationToken).ConfigureAwait(false);

            namedScopes[ScopePath.CONVERSATION] = await conversationScope.GetAsync(context, () => new Dictionary <string, object>(StringComparer.InvariantCultureIgnoreCase), cancellationToken : cancellationToken).ConfigureAwait(false);

            namedScopes[ScopePath.TURN] = new Dictionary <string, object>(StringComparer.InvariantCultureIgnoreCase);

            // Create DialogContext
            var dc = new DialogContext(this.dialogSet, context, dialogState);

            DialogTurnResult turnResult = null;

            if (dc.ActiveDialog == null)
            {
                // start root dialog
                turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
            }
            else
            {
                // Continue execution
                // - This will apply any queued up interruptions and execute the current/next step(s).
                turnResult = await dc.ContinueDialogAsync(cancellationToken : cancellationToken).ConfigureAwait(false);

                if (turnResult.Status == DialogTurnStatus.Empty)
                {
                    // restart root dialog
                    turnResult = await dc.BeginDialogAsync(this.rootDialogId, cancellationToken : cancellationToken).ConfigureAwait(false);
                }
            }

            // send trace of memory
            await dc.Context.SendActivityAsync((Activity)Activity.CreateTraceActivity("BotState", "https://www.botframework.com/schemas/botState", dc.State.GetMemorySnapshot(), "Bot State")).ConfigureAwait(false);

            return(new DialogManagerResult()
            {
                TurnResult = turnResult
            });
        }