private static SkillDialog CreateEchoSkillDialog(ConversationState conversationState, SkillConversationIdFactoryBase conversationIdFactory, SkillHttpClient skillClient, IConfiguration configuration) { var botId = configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value; //if (string.IsNullOrWhiteSpace(botId)) //{ // throw new ArgumentException($"{MicrosoftAppCredentials.MicrosoftAppIdKey} is not in configuration"); //} var skillHostEndpoint = configuration.GetSection("SkillHostEndpoint")?.Value; if (string.IsNullOrWhiteSpace(skillHostEndpoint)) { throw new ArgumentException("SkillHostEndpoint is not in configuration"); } var skillInfo = configuration.GetSection("EchoSkillInfo").Get <BotFrameworkSkill>() ?? throw new ArgumentException("EchoSkillInfo is not set in configuration"); var skillDialogOptions = new SkillDialogOptions { BotId = botId, ConversationIdFactory = conversationIdFactory, SkillClient = skillClient, SkillHostEndpoint = new Uri(skillHostEndpoint), ConversationState = conversationState, Skill = skillInfo }; var echoSkillDialog = new SkillDialog(skillDialogOptions); return(echoSkillDialog); }
public async Task BeginDialogOptionsValidation() { var dialogOptions = new SkillDialogOptions(); var sut = new SkillDialog(dialogOptions); var client = new DialogTestClient(Channels.Test, sut); await Assert.ThrowsExceptionAsync <ArgumentNullException>(async() => await client.SendActivityAsync <IMessageActivity>("irrelevant"), "null options should fail"); client = new DialogTestClient(Channels.Test, sut, new Dictionary <string, string>()); await Assert.ThrowsExceptionAsync <ArgumentException>(async() => await client.SendActivityAsync <IMessageActivity>("irrelevant"), "options should be of type DialogArgs"); client = new DialogTestClient(Channels.Test, sut, new BeginSkillDialogOptions()); await Assert.ThrowsExceptionAsync <ArgumentNullException>(async() => await client.SendActivityAsync <IMessageActivity>("irrelevant"), "Activity in DialogArgs should be set"); }
// Dependency injection uses this constructor to instantiate MainDialog public MainDialog(ConversationState conversationState, SkillConversationIdFactoryBase conversationIdFactory, SkillHttpClient skillClient, SkillsConfiguration skillsConfig, IConfiguration configuration) : base(nameof(MainDialog)) { var botId = configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value; if (string.IsNullOrWhiteSpace(botId)) { throw new ArgumentException($"{MicrosoftAppCredentials.MicrosoftAppIdKey} is not in configuration"); } _skillsConfig = skillsConfig ?? throw new ArgumentNullException(nameof(skillsConfig)); if (skillClient == null) { throw new ArgumentNullException(nameof(skillClient)); } if (conversationState == null) { throw new ArgumentNullException(nameof(conversationState)); } // ChoicePrompt to render available skills and skill actions AddDialog(new ChoicePrompt(nameof(ChoicePrompt))); // SkillDialog used to wrap interaction with the selected skill var skillDialogOptions = new SkillDialogOptions { BotId = botId, ConversationIdFactory = conversationIdFactory, SkillClient = skillClient, SkillHostEndpoint = skillsConfig.SkillHostEndpoint }; AddDialog(new SkillDialog(skillDialogOptions, conversationState)); // Main waterfall dialog for this bot var waterfallSteps = new WaterfallStep[] { SelectSkillStepAsync, SelectSkillActionStepAsync, CallSkillActionStepAsync, FinalStepAsync }; AddDialog(new WaterfallDialog(nameof(WaterfallDialog), waterfallSteps)); // The initial child Dialog to run. InitialDialogId = nameof(WaterfallDialog); }
private async Task RouteToSkillAsync(DialogContext dc, SkillDialogOptions options) { // If we can't handle this within the local Bot it's a skill (prefix of s will make this clearer) if (options.MatchedSkill != null) { // We have matched to a Skill await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"-->Forwarding your utterance to the {options.MatchedSkill.Name} skill.")); // Begin the SkillDialog and pass the arguments in await dc.BeginDialogAsync(nameof(CustomSkillDialog), options); // Pass the activity we have await dc.ContinueDialogAsync(); } }
/// <summary> /// Helper to create a <see cref="SkillDialogOptions"/> for the skillDialog. /// </summary> private static SkillDialogOptions CreateSkillDialogOptions(ConversationState conversationState, Mock <BotFrameworkClient> mockSkillClient) { var dialogOptions = new SkillDialogOptions { BotId = Guid.NewGuid().ToString(), SkillHostEndpoint = new Uri("http://test.contoso.com/skill/messages"), ConversationIdFactory = new SimpleConversationIdFactory(), ConversationState = conversationState, SkillClient = mockSkillClient.Object, Skill = new BotFrameworkSkill { AppId = Guid.NewGuid().ToString(), SkillEndpoint = new Uri("http://testskill.contoso.com/api/messages") } }; return(dialogOptions); }
// Helper method that creates and adds SkillDialog instances for the configured skills. private void AddSkillDialogs(ConversationState conversationState, SkillConversationIdFactoryBase conversationIdFactory, SkillHttpClient skillClient, SkillsConfiguration skillsConfig, string botId) { foreach (var skillInfo in _skillsConfig.Skills.Values) { // Create the dialog options. var skillDialogOptions = new SkillDialogOptions { BotId = botId, ConversationIdFactory = conversationIdFactory, SkillClient = skillClient, SkillHostEndpoint = skillsConfig.SkillHostEndpoint, ConversationState = conversationState, Skill = skillInfo }; // Add a SkillDialog for the selected skill. AddDialog(new SkillDialog(skillDialogOptions, skillInfo.Id)); } }
private async Task RouteToSkillAsync(DialogContext dc, SkillDialogOptions options) { // If we can't handle this within the local Bot it's a skill (prefix of s will make this clearer) if (options.SkillDefinition != null) { // We have matched to a Skill await dc.Context.SendActivityAsync(new Activity(type : ActivityTypes.Trace, text : $"-->Forwarding your utterance to the {options.SkillDefinition.Name} skill.")); // Begin the SkillDialog and pass the arguments in await dc.BeginDialogAsync(options.SkillDefinition.Id, options); // Pass the activity we have var result = await dc.ContinueDialogAsync(); if (result.Status == DialogTurnStatus.Complete) { await CompleteAsync(dc); } } }
public void InitSkills() { // Add Fake Skill registration const string fakeSkillName = "FakeSkill"; var fakeSkillDefinition = new SkillDefinition(); var fakeSkillType = typeof(FakeSkill.FakeSkill); fakeSkillDefinition.Assembly = fakeSkillType.AssemblyQualifiedName; fakeSkillDefinition.Id = fakeSkillName; fakeSkillDefinition.Name = fakeSkillName; SkillConfigurations.Add(fakeSkillDefinition.Id, Services); // Options are passed to the SkillDialog SkillDialogOptions = new SkillDialogOptions(); SkillDialogOptions.SkillDefinition = fakeSkillDefinition; // Add the SkillDialog to the available dialogs passing the initialized FakeSkill Dialogs.Add(new SkillDialog(fakeSkillDefinition, Services, null, TelemetryClient)); }
public void InitSkills() { // Add Fake Skill registration const string fakeSkillName = "FakeSkill"; var fakeSkillDefinition = new SkillDefinition(); var fakeSkillType = typeof(FakeSkill.FakeSkill); fakeSkillDefinition.Id = fakeSkillName; fakeSkillDefinition.Name = fakeSkillName; // Set Assembly name to invalid value fakeSkillDefinition.Assembly = "FakeSkill.FakeSkil, Microsoft.Bot.Solutions.Tests, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null"; SkillConfigurations.Add(fakeSkillDefinition.Id, Services); // Options are passed to the SkillDialog SkillDialogOptions = new SkillDialogOptions(); SkillDialogOptions.SkillDefinition = fakeSkillDefinition; // Add the SkillDialog to the available dialogs passing the initialized FakeSkill Dialogs.Add(new SkillDialog(fakeSkillDefinition, Services, null, null, TelemetryClient, null)); }
/// <summary> /// Create a TestFlow which spins up a CustomSkillDialog ready for the tests to execute against /// </summary> /// <param name="locale"></param> /// <param name="overrideSkillDialogOptions"></param> /// <returns></returns> public TestFlow GetTestFlow(string locale = null, SkillDialogOptions overrideSkillDialogOptions = null) { var adapter = new TestAdapter(sendTraceActivity: true) .Use(new AutoSaveStateMiddleware(ConversationState)); var testFlow = new TestFlow(adapter, async(context, cancellationToken) => { var dc = await Dialogs.CreateContextAsync(context); if (dc.ActiveDialog != null) { var result = await dc.ContinueDialogAsync(); } else { var options = overrideSkillDialogOptions ?? SkillDialogOptions; await dc.BeginDialogAsync(options.SkillDefinition.Id, options); var result = await dc.ContinueDialogAsync(); } }); return(testFlow); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Configure MVC services.AddControllers().AddNewtonsoftJson(); services.AddSingleton(Configuration); // Load settings var settings = new BotSettings(); Configuration.Bind(settings); services.AddSingleton(settings); // Configure channel provider services.AddSingleton <IChannelProvider, ConfigurationChannelProvider>(); // Configure configuration provider services.AddSingleton <ICredentialProvider, ConfigurationCredentialProvider>(); // Register the skills configuration class. var skillsConfig = new SkillsConfiguration(Configuration); services.AddSingleton(skillsConfig); // Register AuthConfiguration to enable custom claim validation. services.AddSingleton(sp => new AuthenticationConfiguration { ClaimsValidator = new AllowedCallersClaimsValidator(skillsConfig) }); // Configure telemetry services.AddApplicationInsightsTelemetry(); services.AddSingleton <IBotTelemetryClient, BotTelemetryClient>(); services.AddSingleton <ITelemetryInitializer, OperationCorrelationTelemetryInitializer>(); services.AddSingleton <ITelemetryInitializer, TelemetryBotIdInitializer>(); services.AddSingleton <TelemetryInitializerMiddleware>(); services.AddSingleton <TelemetryLoggerMiddleware>(); // Configure bot services services.AddSingleton <BotServices>(); // Configure storage // Uncomment the following line for local development without Cosmos Db // services.AddSingleton<IStorage, MemoryStorage>(); services.AddSingleton <IStorage>(new CosmosDbPartitionedStorage(settings.CosmosDb)); services.AddSingleton <UserState>(); services.AddSingleton <ConversationState>(); // Configure localized responses var localizedTemplates = new Dictionary <string, string>(); var templateFile = "AllResponses"; var supportedLocales = new List <string>() { "en-us", "de-de", "es-es", "fr-fr", "it-it", "zh-cn" }; foreach (var locale in supportedLocales) { // LG template for en-us does not include locale in file extension. var localeTemplateFile = locale.Equals("en-us") ? Path.Combine(".", "Responses", $"{templateFile}.lg") : Path.Combine(".", "Responses", $"{templateFile}.{locale}.lg"); localizedTemplates.Add(locale, localeTemplateFile); } services.AddSingleton(new LocaleTemplateManager(localizedTemplates, settings.DefaultLocale ?? "en-us")); // Register the Bot Framework Adapter with error handling enabled. // Note: some classes use the base BotAdapter so we add an extra registration that pulls the same instance. services.AddSingleton <BotFrameworkHttpAdapter, DefaultAdapter>(); services.AddSingleton <BotAdapter>(sp => sp.GetService <BotFrameworkHttpAdapter>()); // Register the skills conversation ID factory, the client and the request handler. services.AddSingleton <SkillConversationIdFactoryBase, SkillConversationIdFactory>(); services.AddHttpClient <SkillHttpClient>(); services.AddSingleton <ChannelServiceHandler, TokenExchangeSkillHandler>(); // Register dialogs services.AddTransient <MainDialog>(); services.AddTransient <SwitchSkillDialog>(); services.AddTransient <OnboardingDialog>(); // Register the SkillDialogs (remote skills). var botId = Configuration.GetSection(MicrosoftAppCredentials.MicrosoftAppIdKey)?.Value; if (string.IsNullOrWhiteSpace(botId)) { throw new ArgumentException($"{MicrosoftAppCredentials.MicrosoftAppIdKey} is not in configuration"); } foreach (var skill in skillsConfig.Skills.Values) { services.AddSingleton(sp => { var skillDialogOptions = new SkillDialogOptions { BotId = botId, ConversationIdFactory = sp.GetService <SkillConversationIdFactoryBase>(), SkillClient = sp.GetService <SkillHttpClient>(), SkillHostEndpoint = skillsConfig.SkillHostEndpoint, Skill = skill, ConversationState = sp.GetService <ConversationState>() }; return(new SkillDialog(skillDialogOptions, skill.Id)); }); } // Configure TokenExchangeConfig for SSO if (settings.TokenExchangeConfig != null) { services.AddSingleton <ITokenExchangeConfig>(settings.TokenExchangeConfig); } // Configure bot services.AddTransient <IBot, DefaultActivityHandler <MainDialog> >(); }