Ejemplo n.º 1
0
        /// <summary>
        /// All subsequent messages are forwarded on to the skill.
        /// </summary>
        /// <param name="innerDc">Inner Dialog Context.</param>
        /// <param name="cancellationToken">Cancellation Token.</param>
        /// <returns>DialogTurnResult.</returns>
        protected override async Task <DialogTurnResult> OnContinueDialogAsync(DialogContext innerDc, CancellationToken cancellationToken = default(CancellationToken))
        {
            var activity = innerDc.Context.Activity;

            if (_authDialog != null && innerDc.ActiveDialog?.Id == _authDialog.Id)
            {
                // Handle magic code auth
                var result = await innerDc.ContinueDialogAsync(cancellationToken);

                // forward the token response to the skill
                if (result.Status == DialogTurnStatus.Complete && result.Result is ProviderTokenResponse)
                {
                    activity.Type  = ActivityTypes.Event;
                    activity.Name  = TokenEvents.TokenResponseEventName;
                    activity.Value = result.Result as ProviderTokenResponse;
                }
                else
                {
                    return(result);
                }
            }

            var dialogResult = await ForwardToSkillAsync(innerDc, activity);

            // if there's any response we need to send to the skill queued
            // forward to skill and start a new turn
            while (_queuedResponses.Count > 0)
            {
                await ForwardToSkillAsync(innerDc, _queuedResponses.Dequeue());
            }

            _skillTransport.Disconnect();

            return(dialogResult);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// When a SkillDialog is started, a skillBegin event is sent which firstly indicates the Skill is being invoked in Skill mode, also slots are also provided where the information exists in the parent Bot.
        /// </summary>
        /// <param name="innerDc">inner dialog context.</param>
        /// <param name="options">options.</param>
        /// <param name="cancellationToken">cancellation token.</param>
        /// <returns>dialog turn result.</returns>
        protected override async Task <DialogTurnResult> OnBeginDialogAsync(DialogContext innerDc, object options = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            var slots = new Dictionary <string, JObject>();

            // Retrieve the SkillContext state object to identify slots (parameters) that can be used to slot-fill when invoking the skill
            var accessor     = _userState.CreateProperty <SkillContext>(nameof(SkillContext));
            var skillContext = await accessor.GetAsync(innerDc.Context, () => new SkillContext());

            /*  In instances where the caller is able to identify/specify the action we process the Action specific slots
             *  In other scenarios (aggregated skill dispatch) we evaluate all possible slots against context and pass across
             *  enabling the Skill to perform it's own action identification. */

            var actionName = options != null ? options as string : null;

            if (actionName != null)
            {
                // Find the specified within the selected Skill for slot filling evaluation
                var action = _skillManifest.Actions.SingleOrDefault(a => a.Id == actionName);
                if (action != null)
                {
                    // If the action doesn't define any Slots or SkillContext is empty then we skip slot evaluation
                    if (action.Definition.Slots != null && skillContext.Count > 0)
                    {
                        // Match Slots to Skill Context
                        slots = await MatchSkillContextToSlots(innerDc, action.Definition.Slots, skillContext);
                    }
                }
                else
                {
                    throw new ArgumentException($"Passed Action ({actionName}) could not be found within the {_skillManifest.Id} skill manifest action definition.");
                }
            }
            else
            {
                // The caller hasn't got the capability of identifying the action as well as the Skill so we enumerate
                // actions and slot data to pass what we have

                // Retrieve a distinct list of all slots, some actions may use the same slot so we use distinct to ensure we only get 1 instance.
                var skillSlots = _skillManifest.Actions.SelectMany(s => s.Definition.Slots).Distinct(new SlotEqualityComparer());
                if (skillSlots != null)
                {
                    // Match Slots to Skill Context
                    slots = await MatchSkillContextToSlots(innerDc, skillSlots.ToList(), skillContext);
                }
            }

            await innerDc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"-->Handing off to the {_skillManifest.Name} skill."));

            var activity = innerDc.Context.Activity;

            var entities = new Dictionary <string, Entity>();

            foreach (var value in slots)
            {
                entities.Add(value.Key, new Entity {
                    Properties = JObject.FromObject(value.Value)
                });
            }

            var semanticAction = new SemanticAction {
                Entities = new Dictionary <string, Entity>()
            };

            foreach (var slot in slots)
            {
                semanticAction.Entities.Add(slot.Key, new Entity {
                    Properties = slot.Value
                });
            }

            activity.SemanticAction = semanticAction;

            // Send skillBegin event to Skill/Bot
            var dialogResult = await ForwardToSkillAsync(innerDc, activity);

            // return APIResponse if any
            if (_apiResponses != null && _apiResponses.Count > 0)
            {
                dialogResult.Result = _apiResponses;

                _skillTransport.Disconnect();

                return(await innerDc.EndDialogAsync(_apiResponses));
            }

            // if there's any response we need to send to the skill queued
            // forward to skill and start a new turn
            while (_queuedResponses.Count > 0)
            {
                await ForwardToSkillAsync(innerDc, _queuedResponses.Dequeue());
            }

            _skillTransport.Disconnect();

            return(dialogResult);
        }