Iciclecreek.Bot.Builder.Dialogs 4.20.11

dotnet add package Iciclecreek.Bot.Builder.Dialogs --version 4.20.11
NuGet\Install-Package Iciclecreek.Bot.Builder.Dialogs -Version 4.20.11
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Iciclecreek.Bot.Builder.Dialogs" Version="4.20.11" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Iciclecreek.Bot.Builder.Dialogs --version 4.20.11
#r "nuget: Iciclecreek.Bot.Builder.Dialogs, 4.20.11"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Iciclecreek.Bot.Builder.Dialogs as a Cake Addin
#addin nuget:?package=Iciclecreek.Bot.Builder.Dialogs&version=4.20.11

// Install Iciclecreek.Bot.Builder.Dialogs as a Cake Tool
#tool nuget:?package=Iciclecreek.Bot.Builder.Dialogs&version=4.20.11

Overview

This library provides two classes

  • IcyBot - An IBot implementation for code first bots without adaptive infrastructure dependencies.
  • IcyDialog - A dialog which simplifies the creation of code based recognizer based dialogs

IBot

The library provides a default IBot implementation that uses dependency injection to get the dialogs. The root dialog is the first Dialog registered in DI.

There is a service extension AddIcyBot() which registers the bot and ensures that state/memory scopes are registered.

The AddPrompts() DI method injects prompts as dialog classes (the Bot Framework dialog requires you to pass in id, instead of class name.)

var sp = new ServiceCollection()
    .AddSingleton<IStorage,MemoryStorage>() // or whatever storage you want.
    .AddDialog<TestDialog>()
    .AddDialog<FooDialog>()
    .AddIcyBot()
    .BuildServiceProvider();

NOTE 1: This bot is not set up to handle skills, lg, etc. If you want all of that stuff you should use an the Adaptive.Runtime

NOTE 2: IcyDialog runs fine in any IBot implementation, you do not need to use IcyBot.

IcyDialog

IcyDialog encapsulates a number of patterns together to make a great base class for creating code-first dialogs.

Dialog methods

  • OnBeginDialogAsync() - called when dialog is started.
  • OnEvaluateStateAsync() - called when no dialog action is taken (including WaitForInput(). This gives you a place to inspect your state and decide to prompt the user for information, regardless of how the state was changed.
  • OnPromptCompletedAsync()/OnPromptCanceledAsync - called when a child dialog completes with a result/canceled.

There is a new dc helper method dc.PromptAsync<DialogT>(property, options)

This method is a enhancement over calling BeginDialog, because it models a dialogs purpose to gather information for a property in memory.The problem with BeginDialog is you have to track what dialog was invoked when you get a resume dialog to continue execution.

The OnPromptCompletedAsync() method is passed the property name and the default behavior for OnPromptCompletedAsync() is to set the property name to the value that is returned. This gives you nice a clean behavior

  • you know what dialog (the one for the property) is completing
  • you get out of the box default behavior which is saves the result in the property you pass.
  • you have a natural place to acknowledge the value you just received.
    // when this prompt completes the the property "this.name" = result from the child dialog
    await PromptAsync<TextPrompt>("this.name", new PromptOptions(){ ... });

OnEvaluateStateAsync() can then be used to decide what the next prompt is needed for the user.

Text Methods

There are 2 dc extension methods for managing sending reples.

  • dc.AppendReplyText() - adds a new line of text to the response.
  • dc.SendReplyText() - send any reply text which has been accumlated. They both take variations of adaptive expression string interpolations one of which will be randonly selected and be evaluated.

Example

   // will pick one of these and add to the replyText as a new line.
   dc.AppendReplyText("Hi!", "Hello ${user.name}!", "Greetings");
   dc.AppendReplyText("Now we need to gather some info!", "I need some facts!", "A couple of questions...");
   await dc.SendReplyText("Here go!", "Let's get started..."); // send queued up text.

Memory methods

You can query for a property changing using dc.IsStateChanged(path) method.

   if (dc.IsStateChanged("dialog.name"))
   {
       // do something...
   }

Entities methods

You can query for the value of an entity using GetEntities and a JsonPath.

  var age = recognizerResult.GetEntities<int?>("$..number..value").FirstOrDefault();

Activity methods

  • OnTurnAsync() - The default OnTurnAsync() implementation will dispatch to strongly typed virtual methods (like ActivityHandler), but with DialogContext instead of TurnContext:

    • OnMessageActivityAsync(dc)
    • OnEndOfConversationAsync(dc)
    • OnMessageReactionActivityAsync(dc)
    • OnAdaptiveCardInvoke(dc)
    • etc.
  • The default OnMessageActivity() implementation invokes the Recognizer and routes the activity using OnRecognizedIntentAsync()/OnUnrecognizedIntentAsync() methods

  • The default OnRecognizedIntentAsync() implementation will resolve methods to intent handlers using the following naming pattern:

protected Task<DialogTurnResult> OnXXXIntent(DialogContext dc, IMessageActivity messageActivity, TopScore topSCore, CancellationToken ct);

Examples:

  • "Greeting" intent ⇒ OnGreetingIntent(dc, IMessageActivity, topScore, cancellationToken)
  • "Goodbye" intent ⇒ OnGoodbyeIntent(dc, IMessageActivity, topScore, cancellationToken)
  • "None" or empty intents ⇒ OnUnrecognizedIntent(dc, IMessageActivity, cancallationToken)

Sample dialog:

    internal class PromptTest : IcyDialog
    {
        public PromptTest()
        {
            this.Recognizer = new LucyRecognizer()
            {
                Intents = new List<string>() { "Greeting", "QueryName" },
                Model = YamlConvert.DeserializeObject<LucyDocument>(
@"
entities:
  - name: Greeting
    patterns:
      - hi

  - name: QueryName
    patterns:
      - what is my name
")
            };
        }



        protected async virtual Task<DialogTurnResult> OnGreetingIntent(DialogContext dc, IMessageActivity messageActivity, RecognizerResult recognizerResult, CancellationToken cancellationToken)
        {
            await dc.SendActivityAsync($"Hi!");
            return await OnEvaluateStateAsync(dc, cancellationToken);
        }

        protected async virtual Task<DialogTurnResult> OnQueryNameIntent(DialogContext dc, IMessageActivity messageActivity, RecognizerResult recognizerResult, CancellationToken cancellationToken)
        {
            var name = ObjectPath.GetPathValue<String>(dc.State, "this.name");
            if (name == null)
            {
                await dc.SendActivityAsync($"I don't know your name.");
            }
            else
            {
                await dc.SendActivityAsync($"Your name is {name}.");
            }
            return await OnEvaluateStateAsync(dc, cancellationToken);
        }

        protected async override Task<DialogTurnResult> OnEvaluateStateAsync(DialogContext dc, CancellationToken ct)
        {
            // if we are missing this.name, prompt for it.
            ObjectPath.TryGetPathValue<String>(dc.State, "this.name", out var name);
            if (String.IsNullOrEmpty(name))
            {
                return await PromptAsync<TextPrompt>(dc, "this.name", new PromptOptions() { Prompt = dc.CreateReply("What is your name?") });
            }

            // if we are missing... prompt for it.
            // ...

            // if we are all done, let's end the dialog...
            // return dc.EndDialogAsync(this);

            return await dc.WaitForInputAsync();
        }

        // hook this to use the name we got from the prompt in a greeting back to the user.
        protected override async Task<DialogTurnResult> OnPromptCompletedAsync(DialogContext dc, string property, object result, CancellationToken cancellationToken = default)
        {
            switch (property)
            {
                case "this.name":
                    await dc.SendActivityAsync($"Nice to meet you {result}!");
                    break;
            }
            return await base.OnPromptCompletedAsync(dc, property, result, cancellationToken); ;
        }

        protected override async Task<DialogTurnResult> OnEndOfConversationActivityAsync(DialogContext dc, IEndOfConversationActivity endOfConversationActivity, CancellationToken cancellationToken)
        {
            return await dc.CancelAllDialogsAsync();
        }
    }
}

Cascading call pattern

IcyDialog splits processes input in cascading calls which will end at the point that a dailog action (BeginDailog/EndDialog/CancelDialog/WaitForInput).

The method pattern processing looks like this:

BeginDialog()
    => OnBeginDialog()
        => OnTurnAsync()
            => OnMessageActivity()
                => OnRecognizedIntent()
                    => OnXXXIntent()
                        =>OnEvaluateStateAsync()
                => OnUnrecognizedIntent()
                    => OnEvaluateStateAsync()
            => OnTypingActivity()
                => OnEvaluateStateAsync()
            => ...
ContinueDialog()
    => OnContinueDialog()
        => OnTurnAsync()
            => OnMessageActivity()
                => OnRecognizedIntent()
                    => OnXXXIntent()
                        =>OnEvaluateStateAsync()
                => OnUnrecognizedIntent()
                    => OnEvaluateStateAsync()
            => OnTypingActivity()
                => OnEvaluateStateAsync()
            => ...
ResumeDialog()
    => OnResumeDialog()
        => OnPromptCompletedAsync() 
            => OnEvaluateStateAsync()
        => OnPromptCanceledAsync() 
            => OnEvaluteAsync()
        => OnEvaluateStateAsync()

Extension Helpers

The library includes some helpful extensions to reduce typing.

  • dc.SaveOptions(options) and dc.GetOptions<T>() - methods for capturing and retrieving the options
  • dc.WaitForInputAsync() - signal that your dialog is waiting input.
  • dc.SendActivity() - shortcut for dc.Context.SendActivity()
  • dc.BeginDialog<DialogT>() - begins a dialog assuming that the name of DialogT is the id of the dialog.
  • dialogSet.Add<DialogT>() - Add an instance of dialogT to a dialogset
  • dc.IsPathChanged(path) - well return true if the path has changed this turn.
  • recognizer.GetEntities<T>(JsonPath) - will return resolved value for entities.
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
4.20.11 158 5/26/2023
4.20.0 144 6/16/2023
4.19.11 132 5/25/2023
4.19.10 131 5/25/2023
4.19.9 135 5/16/2023
4.19.8 126 5/13/2023
4.19.7 121 5/13/2023
4.19.6 124 5/13/2023
4.19.5 141 5/13/2023
4.19.4 131 5/12/2023
4.19.3 146 5/11/2023
4.19.2 156 5/2/2023
4.19.0 196 4/15/2023
4.16.7 405 5/8/2022
4.16.6 385 5/6/2022
4.16.5 402 5/5/2022
4.16.4 390 5/2/2022
4.16.3 385 5/1/2022
4.16.2-preview 135 4/27/2022
4.16.1-preview 142 4/27/2022
4.16.0-preview 136 4/26/2022