Esempio n. 1
0
        /// <summary>
        /// Map Skill slots to what we have in SkillContext.
        /// </summary>
        /// <param name="innerDc">Dialog Contect.</param>
        /// <param name="actionSlots">The Slots within an Action.</param>
        /// <param name="skillContext">Calling Bot's SkillContext.</param>
        /// <returns>A filtered SkillContext for the Skill.</returns>
        private async Task <SkillContext> MatchSkillContextToSlots(DialogContext innerDc, List <Slot> actionSlots, SkillContext skillContext)
        {
            SkillContext slots = new SkillContext();

            if (actionSlots != null)
            {
                foreach (Slot slot in actionSlots)
                {
                    // For each slot we check to see if there is an exact match, if so we pass this slot across to the skill
                    if (skillContext.TryGetValue(slot.Name, out object slotValue))
                    {
                        slots.Add(slot.Name, slotValue);

                        // Send trace to emulator
                        await innerDc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"-->Matched the {slot.Name} slot within SkillContext and passing to the Skill."));
                    }
                }
            }

            return(slots);
        }
Esempio 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))
        {
            SkillContext slots = new SkillContext();

            // 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 skillBeginEvent = new Activity(
                type: ActivityTypes.Event,
                channelId: activity.ChannelId,
                from: new ChannelAccount(id: activity.From.Id, name: activity.From.Name),
                recipient: new ChannelAccount(id: activity.Recipient.Id, name: activity.Recipient.Name),
                conversation: new ConversationAccount(id: activity.Conversation.Id),
                name: SkillEvents.SkillBeginEventName,
                value: slots);

            // Send skillBegin event to Skill/Bot
            return(await ForwardToSkillAsync(innerDc, skillBeginEvent));
        }